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:
John Kessenich 2014-06-18 23:02:00 +00:00
parent fd30542a0f
commit 7e991e7be1
5 changed files with 113 additions and 56 deletions

View File

@ -155,79 +155,117 @@ void TInputScanner::consumeWhitespaceComment(bool& foundNonSpaceTab)
// 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);
// #
if (get() != '#')
return true;
// whitespace
bool lookingInMiddle = false;
int c;
do {
c = get();
} while (c == ' ' || c == '\t');
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;
if ( c != 'v' ||
get() != 'e' ||
get() != 'r' ||
get() != 's' ||
get() != 'i' ||
get() != 'o' ||
get() != 'n')
return 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;
// whitespace
do {
c = get();
} while (c == ' ' || c == '\t');
// "#"
if (get() != '#') {
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
do {
c = get();
} while (c == ' ' || c == '\t');
// 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;
// "version"
if ( c != 'v' ||
get() != 'e' ||
get() != 'r' ||
get() != 's' ||
get() != 'i' ||
get() != 'o' ||
get() != 'n') {
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;
// whitespace
do {
c = get();
} while (c == ' ' || c == '\t');
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.

View File

@ -112,7 +112,7 @@ public:
void consumeWhiteSpace(bool& foundNonSpaceTab);
bool consumeComment();
void consumeWhitespaceComment(bool& foundNonSpaceTab);
bool scanVersion(int& version, EProfile& profile);
bool scanVersion(int& version, EProfile& profile, bool& notFirstToken);
protected:

View File

@ -461,11 +461,19 @@ bool CompileDeferred(
int version;
EProfile profile;
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 goodVersion = DeduceVersionProfile(compiler->infoSink, compiler->getLanguage(), versionNotFirst, defaultVersion, version, profile);
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.setProfile(profile);
SetupBuiltinSymbolTable(version, profile);
@ -496,6 +504,12 @@ bool CompileDeferred(
parseContext.setLimits(*resources);
if (! goodVersion)
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();

View File

@ -367,6 +367,10 @@ void TParseContext::requireExtensions(TSourceLoc loc, int numExtensions, const c
bool warned = false;
for (int i = 0; i < numExtensions; ++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) {
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
warned = true;

View File

@ -205,7 +205,8 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
}
} else if (ch == 'f' || ch == 'F') {
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)
parseContext.error(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
if (len < TPpToken::maxTokenLength)