Implement our own routine to turn C99-style hexadecimal float constants in strong form into floating-point values. With this, we can correctly handle hex float constants on Windows, where the builtin atof() routine just returns zero for them. Fixes issue #16.
This commit is contained in:
91
lex.ll
91
lex.ll
@@ -45,6 +45,7 @@ static void lCComment(SourcePos *);
|
||||
static void lCppComment(SourcePos *);
|
||||
static void lHandleCppHash(SourcePos *);
|
||||
static void lStringConst(YYSTYPE *, SourcePos *);
|
||||
static double lParseHexFloat(const char *ptr);
|
||||
|
||||
#define YY_USER_ACTION \
|
||||
yylloc->first_line = yylloc->last_line; \
|
||||
@@ -65,7 +66,8 @@ inline int isatty(int) { return 0; }
|
||||
|
||||
WHITESPACE [ \t\r]+
|
||||
INT_NUMBER (([0-9]+)|(0x[0-9a-fA-F]+)|(0b[01]+))
|
||||
FLOAT_NUMBER (([0-9]+|(([0-9]+\.[0-9]*[fF]?)|(\.[0-9]+)))([eE][-+]?[0-9]+)?[fF]?)|([-]?0x[01]\.?[0-9a-fA-F]+p[-+]?[0-9]+[fF]?)
|
||||
FLOAT_NUMBER (([0-9]+|(([0-9]+\.[0-9]*[fF]?)|(\.[0-9]+)))([eE][-+]?[0-9]+)?[fF]?)
|
||||
HEX_FLOAT_NUMBER (0x[01](\.[0-9a-fA-F]*)?p[-+]?[0-9]+[fF]?)
|
||||
|
||||
IDENT [a-zA-Z_][a-zA-Z_0-9]*
|
||||
|
||||
@@ -182,13 +184,15 @@ L?\"(\\.|[^\\"])*\" { lStringConst(yylval, yylloc); return TOKEN_STRING_LITERAL;
|
||||
}
|
||||
|
||||
{FLOAT_NUMBER} {
|
||||
/* FIXME: need to implement a hex float constant parser so that we can
|
||||
support them on Windows (which doesn't handle them in its atof()
|
||||
implementation... */
|
||||
yylval->floatVal = atof(yytext);
|
||||
return TOKEN_FLOAT_CONSTANT;
|
||||
}
|
||||
|
||||
{HEX_FLOAT_NUMBER} {
|
||||
yylval->floatVal = lParseHexFloat(yytext);
|
||||
return TOKEN_FLOAT_CONSTANT;
|
||||
}
|
||||
|
||||
"++" { return TOKEN_INC_OP; }
|
||||
"--" { return TOKEN_DEC_OP; }
|
||||
"<<" { return TOKEN_LEFT_OP; }
|
||||
@@ -424,3 +428,82 @@ lStringConst(YYSTYPE *yylval, SourcePos *pos)
|
||||
}
|
||||
yylval->stringVal = new std::string(str);
|
||||
}
|
||||
|
||||
|
||||
/** Compute the value 2^n, where the exponent is given as an integer.
|
||||
There are more efficient ways to do this, for example by just slamming
|
||||
the bits into the appropriate bits of the double, but let's just do the
|
||||
obvious thing.
|
||||
*/
|
||||
static double
|
||||
ipow2(int exponent) {
|
||||
if (exponent < 0)
|
||||
return 1. / ipow2(-exponent);
|
||||
|
||||
double ret = 1.;
|
||||
while (exponent > 16) {
|
||||
ret *= 65536.;
|
||||
exponent -= 16;
|
||||
}
|
||||
while (exponent-- > 0)
|
||||
ret *= 2.;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/** Parse a hexadecimal-formatted floating-point number (C99 hex float
|
||||
constant-style).
|
||||
*/
|
||||
static double
|
||||
lParseHexFloat(const char *ptr) {
|
||||
assert(ptr != NULL);
|
||||
|
||||
assert(ptr[0] == '0' && ptr[1] == 'x');
|
||||
ptr += 2;
|
||||
|
||||
// Start initializing the mantissa
|
||||
assert(*ptr == '0' || *ptr == '1');
|
||||
double mantissa = (*ptr == '1') ? 1. : 0.;
|
||||
++ptr;
|
||||
|
||||
if (*ptr == '.') {
|
||||
// Is there a fraction part? If so, the i'th digit we encounter
|
||||
// gives the 1/(16^i) component of the mantissa.
|
||||
++ptr;
|
||||
|
||||
double scale = 1. / 16.;
|
||||
// Keep going until we come to the 'p', which indicates that we've
|
||||
// come to the exponent
|
||||
while (*ptr != 'p') {
|
||||
// Figure out the raw value from 0-15
|
||||
int digit;
|
||||
if (*ptr >= '0' && *ptr <= '9')
|
||||
digit = *ptr - '0';
|
||||
else if (*ptr >= 'a' && *ptr <= 'f')
|
||||
digit = 10 + *ptr - 'a';
|
||||
else {
|
||||
assert(*ptr >= 'A' && *ptr <= 'F');
|
||||
digit = 10 + *ptr - 'A';
|
||||
}
|
||||
|
||||
// And add its contribution to the mantissa
|
||||
mantissa += scale * digit;
|
||||
scale /= 16.;
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
// If there's not a '.', then we better be going straight to the
|
||||
// exponent
|
||||
assert(*ptr == 'p');
|
||||
|
||||
++ptr; // skip the 'p'
|
||||
|
||||
// interestingly enough, the exponent is provided base 10..
|
||||
int exponent = (int)strtol(ptr, (char **)NULL, 10);
|
||||
|
||||
// Does stdlib exp2() guarantee exact results for integer n where can
|
||||
// be represented exactly as doubles? I would hope so but am not sure,
|
||||
// so let's be sure.
|
||||
return mantissa * ipow2(exponent);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user