PP: Clean up and rationalize floating-point-number scanner.

This encapsulates where the string could overflow, removing 40 lines
of fragile code.  It also improves handling of numbers that are too long.

There are a couple of open issues that could related to this function
being more rational (locale dependence, 1.#INF).
This commit is contained in:
John Kessenich 2017-01-12 12:00:59 -07:00
parent e86fc0946f
commit 913e3b686a
3 changed files with 73 additions and 112 deletions

View file

@ -100,36 +100,26 @@ namespace glslang {
int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
{
bool HasDecimalOrExponent = false;
int declen;
int str_len;
int isDouble = 0;
#ifdef AMD_EXTENSIONS
int isFloat16 = 0;
bool enableFloat16 = parseContext.version >= 450 && parseContext.extensionTurnedOn(E_GL_AMD_gpu_shader_half_float);
#endif
declen = 0;
const auto saveName = [&](int ch) {
if (len <= MaxTokenLength)
ppToken->name[len++] = static_cast<char>(ch);
};
// Decimal:
str_len=len;
char* str = ppToken->name;
if (ch == '.') {
HasDecimalOrExponent = true;
str[len++] = (char)ch;
saveName(ch);
ch = getChar();
while (ch >= '0' && ch <= '9') {
if (len < MaxTokenLength) {
declen++;
if (len > 0 || ch != '0') {
str[len] = (char)ch;
len++;
str_len++;
}
ch = getChar();
} else {
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
len = 1;
str_len = 1;
}
saveName(ch);
ch = getChar();
}
}
@ -137,101 +127,74 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
if (ch == 'e' || ch == 'E') {
HasDecimalOrExponent = true;
if (len >= MaxTokenLength) {
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
len = 1;
str_len = 1;
} else {
str[len++] = (char)ch;
saveName(ch);
ch = getChar();
if (ch == '+' || ch == '-') {
saveName(ch);
ch = getChar();
if (ch == '+') {
str[len++] = (char)ch;
ch = getChar();
} else if (ch == '-') {
str[len++] = (char)ch;
}
if (ch >= '0' && ch <= '9') {
while (ch >= '0' && ch <= '9') {
saveName(ch);
ch = getChar();
}
if (ch >= '0' && ch <= '9') {
while (ch >= '0' && ch <= '9') {
if (len < MaxTokenLength) {
str[len++] = (char)ch;
ch = getChar();
} else {
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
len = 1;
str_len = 1;
}
}
} else {
parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
}
} else {
parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
}
}
if (len == 0) {
ppToken->dval = 0.0;
strcpy(str, "0.0");
} else {
if (ch == 'l' || ch == 'L') {
parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
if (! HasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
int ch2 = getChar();
if (ch2 != 'f' && ch2 != 'F') {
ungetChar();
ungetChar();
} else {
if (len < MaxTokenLength) {
str[len++] = (char)ch;
str[len++] = (char)ch2;
isDouble = 1;
} else {
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
len = 1,str_len=1;
}
}
#ifdef AMD_EXTENSIONS
} else if (enableFloat16 && (ch == 'h' || ch == 'H')) {
parseContext.float16Check(ppToken->loc, "half floating-point suffix");
if (!HasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
int ch2 = getChar();
if (ch2 != 'f' && ch2 != 'F') {
ungetChar();
ungetChar();
}
else {
if (len < MaxTokenLength) {
str[len++] = (char)ch;
str[len++] = (char)ch2;
isFloat16 = 1;
}
else {
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
len = 1, str_len = 1;
}
}
#endif
} else if (ch == 'f' || ch == 'F') {
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
if (! parseContext.relaxedErrors())
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
if (! HasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
if (len < MaxTokenLength)
str[len++] = (char)ch;
else {
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
len = 1,str_len=1;
}
} else
// Suffix:
if (ch == 'l' || ch == 'L') {
parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
if (! HasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
int ch2 = getChar();
if (ch2 != 'f' && ch2 != 'F') {
ungetChar();
ungetChar();
} else {
saveName(ch);
saveName(ch2);
isDouble = 1;
}
#ifdef AMD_EXTENSIONS
} else if (enableFloat16 && (ch == 'h' || ch == 'H')) {
parseContext.float16Check(ppToken->loc, "half floating-point suffix");
if (!HasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
int ch2 = getChar();
if (ch2 != 'f' && ch2 != 'F') {
ungetChar();
ungetChar();
} else {
saveName(ch);
saveName(ch2);
isFloat16 = 1;
}
#endif
} else if (ch == 'f' || ch == 'F') {
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
if (! parseContext.relaxedErrors())
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
if (! HasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
saveName(ch);
} else
ungetChar();
str[len]='\0';
// Patch up the name, length, etc.
ppToken->dval = strtod(str, nullptr);
if (len > MaxTokenLength) {
len = MaxTokenLength;
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
}
ppToken->name[len] = '\0';
// Get the numerical value
ppToken->dval = strtod(ppToken->name, nullptr);
// Return the right token type
if (isDouble)
return PpAtomConstDouble;
#ifdef AMD_EXTENSIONS