Revert "update static void parse_number()"

because:
- Constructing fp numbers isn't quite trivial
- 3 additional calls to strchr per number is noticeable slow

Also: exclude abitest.c:ret_longdouble_test2 on _WIN32
for mixed gcc/tcc scenario

test case:
- make -k test (on win32):
  -2.120000 0.500000 23000000000.000000
  +2.120000 0.500000 22999999999.999996
  ...
  ret_longdouble_test2... failure

This reverts 857f7dbfa6
and deaee6c249
This commit is contained in:
grischka 2014-05-06 18:24:41 +02:00
parent 5e56fb635a
commit 899d26605c
2 changed files with 254 additions and 145 deletions

326
tccpp.c
View file

@ -58,6 +58,7 @@ static const int *unget_saved_macro_ptr;
static int unget_saved_buffer[TOK_MAX_SIZE + 1]; static int unget_saved_buffer[TOK_MAX_SIZE + 1];
static int unget_buffer_enabled; static int unget_buffer_enabled;
static TokenSym *hash_ident[TOK_HASH_SIZE]; static TokenSym *hash_ident[TOK_HASH_SIZE];
static char token_buf[STRING_MAX_SIZE + 1];
/* true if isid(c) || isnum(c) */ /* true if isid(c) || isnum(c) */
static unsigned char isidnum_table[256-CH_EOF]; static unsigned char isidnum_table[256-CH_EOF];
@ -1789,156 +1790,261 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long
cstr_wccat(outstr, '\0'); cstr_wccat(outstr, '\0');
} }
/* we use 64 bit numbers */
#define BN_SIZE 2
/* bn = (bn << shift) | or_val */
static void bn_lshift(unsigned int *bn, int shift, int or_val)
{
int i;
unsigned int v;
for(i=0;i<BN_SIZE;i++) {
v = bn[i];
bn[i] = (v << shift) | or_val;
or_val = v >> (32 - shift);
}
}
static void bn_zero(unsigned int *bn)
{
int i;
for(i=0;i<BN_SIZE;i++) {
bn[i] = 0;
}
}
/* parse number in null terminated string 'p' and return it in the /* parse number in null terminated string 'p' and return it in the
current token */ current token */
static void parse_number(const char *p) static void parse_number(const char *p)
{ {
int b, t, c; int b, t, shift, frac_bits, s, exp_val, ch;
char *q;
unsigned int bn[BN_SIZE];
double d;
c = *p++; /* number */
t = *p++; q = token_buf;
ch = *p++;
t = ch;
ch = *p++;
*q++ = t;
b = 10; b = 10;
if(c=='.'){ if (t == '.') {
--p;
goto float_frac_parse; goto float_frac_parse;
} } else if (t == '0') {
if(c == '0'){ if (ch == 'x' || ch == 'X') {
if (t == 'x' || t == 'X') { q--;
ch = *p++;
b = 16; b = 16;
c = *p++; } else if (tcc_ext && (ch == 'b' || ch == 'B')) {
} else if (tcc_ext && (t == 'b' || t == 'B')) { q--;
ch = *p++;
b = 2; b = 2;
c = *p++;
}else{
--p;
} }
}else }
--p; /* parse all digits. cannot check octal numbers at this stage
if(strchr(p , '.') || (b == 10 && (strchr(p,'e') || strchr(p,'E'))) || because of floating point constants */
((b == 2 || b == 16)&& (strchr(p,'p') || strchr(p,'P')))){ while (1) {
long double ld, sh, fb; if (ch >= 'a' && ch <= 'f')
int exp; t = ch - 'a' + 10;
else if (ch >= 'A' && ch <= 'F')
t = ch - 'A' + 10;
else if (isnum(ch))
t = ch - '0';
else
break;
if (t >= b)
break;
if (q >= token_buf + STRING_MAX_SIZE) {
num_too_long:
tcc_error("number too long");
}
*q++ = ch;
ch = *p++;
}
if (ch == '.' ||
((ch == 'e' || ch == 'E') && b == 10) ||
((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) {
if (b != 10) {
/* NOTE: strtox should support that for hexa numbers, but /* NOTE: strtox should support that for hexa numbers, but
non ISOC99 libcs do not support it, so we prefer to do non ISOC99 libcs do not support it, so we prefer to do
it by hand */ it by hand */
/* hexadecimal or binary floats */ /* hexadecimal or binary floats */
/* XXX: handle overflows */ /* XXX: handle overflows */
float_frac_parse: *q = '\0';
fb = 1.0L/b; if (b == 16)
sh = b; shift = 4;
ld = 0.0;
while(1){
if (c == '\0')
break;
if (c >= 'a' && c <= 'f')
t = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
t = c - 'A' + 10;
else if(isnum(c))
t = c - '0';
else else
shift = 2;
bn_zero(bn);
q = token_buf;
while (1) {
t = *q++;
if (t == '\0') {
break; break;
} else if (t >= 'a') {
t = t - 'a' + 10;
} else if (t >= 'A') {
t = t - 'A' + 10;
} else {
t = t - '0';
}
bn_lshift(bn, shift, t);
}
frac_bits = 0;
if (ch == '.') {
ch = *p++;
while (1) {
t = ch;
if (t >= 'a' && t <= 'f') {
t = t - 'a' + 10;
} else if (t >= 'A' && t <= 'F') {
t = t - 'A' + 10;
} else if (t >= '0' && t <= '9') {
t = t - '0';
} else {
break;
}
if (t >= b) if (t >= b)
tcc_error("invalid digit"); tcc_error("invalid digit");
ld = ld * b + t; bn_lshift(bn, shift, t);
c = *p++; frac_bits += shift;
} ch = *p++;
if (c == '.'){
c = *p++;
sh = fb;
while (1){
if (c == '\0')
break;
if (c >= 'a' && c <= 'f')
t = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
t = c - 'A' + 10;
else if (isnum(c))
t =c - '0';
else
break;
if (t >= b){
if(b == 10 && (c == 'e' || c == 'E' || c == 'f' || c == 'F'))
break;
tcc_error("invalid digit");
}
ld += sh*t;
sh*=fb;
c = *p++;
} }
} }
if ((b == 16 || b == 2) && c != 'p' && c != 'P') if (ch != 'p' && ch != 'P')
expect("exponent"); expect("exponent");
if(((c == 'e' || c == 'E') && b == 10) || ch = *p++;
((c == 'p' || c == 'P') && (b == 16 || b == 2))){ s = 1;
c = *p++; exp_val = 0;
if(c == '+' || c == '-'){ if (ch == '+') {
if (c == '-') ch = *p++;
sh = fb; } else if (ch == '-') {
c = *p++; s = -1;
}else ch = *p++;
sh = b; }
if (!isnum(c)) if (ch < '0' || ch > '9')
expect("exponent digits"); expect("exponent digits");
exp = 0; while (ch >= '0' && ch <= '9') {
do{ exp_val = exp_val * 10 + ch - '0';
exp = exp * 10 + c - '0'; ch = *p++;
c = *p++;
}while(isnum(c));
while (exp != 0){
if (exp & 1)
ld *= sh;
exp >>= 1;
sh *= sh;
} }
} exp_val = exp_val * s;
t = toup(c);
/* now we can generate the number */
/* XXX: should patch directly float number */
d = (double)bn[1] * 4294967296.0 + (double)bn[0];
d = ldexp(d, exp_val - frac_bits);
t = toup(ch);
if (t == 'F') { if (t == 'F') {
c = *p++; ch = *p++;
tok = TOK_CFLOAT; tok = TOK_CFLOAT;
tokc.f = (float)ld; /* float : should handle overflow */
tokc.f = (float)d;
} else if (t == 'L') { } else if (t == 'L') {
c = *p++; ch = *p++;
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
tok = TOK_CDOUBLE; tok = TOK_CDOUBLE;
tokc.d = (double)ld; tokc.d = d;
#else #else
tok = TOK_CLDOUBLE; tok = TOK_CLDOUBLE;
tokc.ld = ld; /* XXX: not large enough */
tokc.ld = (long double)d;
#endif #endif
} else { } else {
tok = TOK_CDOUBLE; tok = TOK_CDOUBLE;
tokc.d = (double)ld; tokc.d = d;
} }
} else { } else {
uint64_t n = 0, n1; /* decimal floats */
int warn = 1; if (ch == '.') {
int lcount, ucount; if (q >= token_buf + STRING_MAX_SIZE)
if (b == 10 && c == '0') { goto num_too_long;
b = 8; *q++ = ch;
ch = *p++;
float_frac_parse:
while (ch >= '0' && ch <= '9') {
if (q >= token_buf + STRING_MAX_SIZE)
goto num_too_long;
*q++ = ch;
ch = *p++;
} }
}
if (ch == 'e' || ch == 'E') {
if (q >= token_buf + STRING_MAX_SIZE)
goto num_too_long;
*q++ = ch;
ch = *p++;
if (ch == '-' || ch == '+') {
if (q >= token_buf + STRING_MAX_SIZE)
goto num_too_long;
*q++ = ch;
ch = *p++;
}
if (ch < '0' || ch > '9')
expect("exponent digits");
while (ch >= '0' && ch <= '9') {
if (q >= token_buf + STRING_MAX_SIZE)
goto num_too_long;
*q++ = ch;
ch = *p++;
}
}
*q = '\0';
t = toup(ch);
errno = 0;
if (t == 'F') {
ch = *p++;
tok = TOK_CFLOAT;
tokc.f = strtof(token_buf, NULL);
} else if (t == 'L') {
ch = *p++;
#ifdef TCC_TARGET_PE
tok = TOK_CDOUBLE;
tokc.d = strtod(token_buf, NULL);
#else
tok = TOK_CLDOUBLE;
tokc.ld = strtold(token_buf, NULL);
#endif
} else {
tok = TOK_CDOUBLE;
tokc.d = strtod(token_buf, NULL);
}
}
} else {
unsigned long long n, n1;
int lcount, ucount;
/* integer number */
*q = '\0';
q = token_buf;
if (b == 10 && *q == '0') {
b = 8;
q++;
}
n = 0;
while(1) { while(1) {
if (c == '\0') t = *q++;
break; /* no need for checks except for base 10 / 8 errors */
if (c >= 'a' && c <= 'f') if (t == '\0') {
t = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
t = c - 'A' + 10;
else if(isnum(c))
t = c - '0';
else
break; break;
} else if (t >= 'a') {
t = t - 'a' + 10;
} else if (t >= 'A') {
t = t - 'A' + 10;
} else {
t = t - '0';
if (t >= b) if (t >= b)
tcc_error("invalid digit"); tcc_error("invalid digit");
}
n1 = n; n1 = n;
n = n * b + t; n = n * b + t;
if (n < n1 && warn){ /* detect overflow */
tcc_warning("integer constant overflow"); /* XXX: this test is not reliable */
warn = 0; if (n < n1)
} tcc_error("integer constant overflow");
c = *p++;
} }
/* XXX: not exactly ANSI compliant */ /* XXX: not exactly ANSI compliant */
if ((n & 0xffffffff00000000LL) != 0) { if ((n & 0xffffffff00000000LL) != 0) {
if ((n >> 63) != 0) if ((n >> 63) != 0)
@ -1953,7 +2059,7 @@ float_frac_parse:
lcount = 0; lcount = 0;
ucount = 0; ucount = 0;
for(;;) { for(;;) {
t = toup(c); t = toup(ch);
if (t == 'L') { if (t == 'L') {
if (lcount >= 2) if (lcount >= 2)
tcc_error("three 'l's in integer constant"); tcc_error("three 'l's in integer constant");
@ -1968,7 +2074,7 @@ float_frac_parse:
#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
} }
#endif #endif
c = *p++; ch = *p++;
} else if (t == 'U') { } else if (t == 'U') {
if (ucount >= 1) if (ucount >= 1)
tcc_error("two 'u's in integer constant"); tcc_error("two 'u's in integer constant");
@ -1977,7 +2083,7 @@ float_frac_parse:
tok = TOK_CUINT; tok = TOK_CUINT;
else if (tok == TOK_CLLONG) else if (tok == TOK_CLLONG)
tok = TOK_CULLONG; tok = TOK_CULLONG;
c = *p++; ch = *p++;
} else { } else {
break; break;
} }
@ -1987,7 +2093,7 @@ float_frac_parse:
else else
tokc.ull = n; tokc.ull = n;
} }
if (c) if (ch)
tcc_error("invalid number\n"); tcc_error("invalid number\n");
} }

View file

@ -486,7 +486,10 @@ int main(int argc, char **argv) {
RUN_TEST(ret_2float_test); RUN_TEST(ret_2float_test);
RUN_TEST(ret_2double_test); RUN_TEST(ret_2double_test);
RUN_TEST(ret_longlong_test2); RUN_TEST(ret_longlong_test2);
#if !defined _WIN32 || !defined __GNUC__
/* on win32, 'long double' is 10-byte with gcc, but is 'double' with tcc/msvc */
RUN_TEST(ret_longdouble_test2); RUN_TEST(ret_longdouble_test2);
#endif
RUN_TEST(reg_pack_test); RUN_TEST(reg_pack_test);
RUN_TEST(reg_pack_longlong_test); RUN_TEST(reg_pack_longlong_test);
RUN_TEST(sret_test); RUN_TEST(sret_test);