update static void parse_number(const char *p) for tccpp.c

This commit is contained in:
jiang 2014-04-28 12:42:36 +08:00
parent 4b50557553
commit 857f7dbfa6

304
tccpp.c
View file

@ -1817,234 +1817,152 @@ static void bn_zero(unsigned int *bn)
current token */ current token */
static void parse_number(const char *p) static void parse_number(const char *p)
{ {
int b, t, shift, frac_bits, s, exp_val, ch; int b, t, c;
char *q;
unsigned int bn[BN_SIZE];
double d;
/* number */ c = *p++;
q = token_buf; t = *p++;
ch = *p++;
t = ch;
ch = *p++;
*q++ = t;
b = 10; b = 10;
if (t == '.') { if(c=='.'){
--p;
goto float_frac_parse; goto float_frac_parse;
} else if (t == '0') { }
if (ch == 'x' || ch == 'X') { if(c == '0'){
q--; if (t == 'x' || t == 'X') {
ch = *p++;
b = 16; b = 16;
} else if (tcc_ext && (ch == 'b' || ch == 'B')) { c = *p++;
q--; } else if (tcc_ext && (t == 'b' || t == 'B')) {
ch = *p++;
b = 2; b = 2;
c = *p++;
}else{
--p;
} }
} }else
/* parse all digits. cannot check octal numbers at this stage --p;
because of floating point constants */ if(strchr(p , '.') || (b == 10 && (strchr(p,'e') || strchr(p,'E'))) ||
while (1) { ((b == 2 || b == 16)&& (strchr(p,'p') || strchr(p,'P')))){
if (ch >= 'a' && ch <= 'f') long double ld, sh, fb;
t = ch - 'a' + 10; int exp;
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 */
*q = '\0';
if (b == 16)
shift = 4;
else
shift = 2;
bn_zero(bn);
q = token_buf;
while (1) {
t = *q++;
if (t == '\0') {
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)
tcc_error("invalid digit");
bn_lshift(bn, shift, t);
frac_bits += shift;
ch = *p++;
}
}
if (ch != 'p' && ch != 'P')
expect("exponent");
ch = *p++;
s = 1;
exp_val = 0;
if (ch == '+') {
ch = *p++;
} else if (ch == '-') {
s = -1;
ch = *p++;
}
if (ch < '0' || ch > '9')
expect("exponent digits");
while (ch >= '0' && ch <= '9') {
exp_val = exp_val * 10 + ch - '0';
ch = *p++;
}
exp_val = exp_val * s;
/* 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') {
ch = *p++;
tok = TOK_CFLOAT;
/* float : should handle overflow */
tokc.f = (float)d;
} else if (t == 'L') {
ch = *p++;
#ifdef TCC_TARGET_PE
tok = TOK_CDOUBLE;
tokc.d = d;
#else
tok = TOK_CLDOUBLE;
/* XXX: not large enough */
tokc.ld = (long double)d;
#endif
} else {
tok = TOK_CDOUBLE;
tokc.d = d;
}
} else {
/* decimal floats */
if (ch == '.') {
if (q >= token_buf + STRING_MAX_SIZE)
goto num_too_long;
*q++ = ch;
ch = *p++;
float_frac_parse: float_frac_parse:
while (ch >= '0' && ch <= '9') { fb = 1.0L/b;
if (q >= token_buf + STRING_MAX_SIZE) sh = b;
goto num_too_long; ld = 0.0;
*q++ = ch;
ch = *p++; 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)
tcc_error("invalid digit");
ld = ld * b + t;
c = *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 (ch == 'e' || ch == 'E') { if ((b == 16 || b == 2) && c != 'p' && c != 'P')
if (q >= token_buf + STRING_MAX_SIZE) expect("exponent");
goto num_too_long; if(((c == 'e' || c == 'E') && b == 10) ||
*q++ = ch; ((c == 'p' || c == 'P') && (b == 16 || b == 2))){
ch = *p++; c = *p++;
if (ch == '-' || ch == '+') { if(c == '+' || c == '-'){
if (q >= token_buf + STRING_MAX_SIZE) if (c == '-')
goto num_too_long; sh = fb;
*q++ = ch; c = *p++;
ch = *p++; }else
} sh = b;
if (ch < '0' || ch > '9') if (!isnum(c))
expect("exponent digits"); expect("exponent digits");
while (ch >= '0' && ch <= '9') { exp = 0;
if (q >= token_buf + STRING_MAX_SIZE) do{
goto num_too_long; exp = exp * 10 + c - '0';
*q++ = ch; c = *p++;
ch = *p++; }while(isnum(c));
while (exp != 0){
if (exp & 1)
ld *= sh;
exp >>= 1;
sh *= sh;
} }
} }
*q = '\0'; t = toup(c);
t = toup(ch);
errno = 0;
if (t == 'F') { if (t == 'F') {
ch = *p++; c = *p++;
tok = TOK_CFLOAT; tok = TOK_CFLOAT;
tokc.f = strtof(token_buf, NULL); tokc.f = (float)ld;
} else if (t == 'L') { } else if (t == 'L') {
ch = *p++; c = *p++;
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
tok = TOK_CDOUBLE; tok = TOK_CDOUBLE;
tokc.d = strtod(token_buf, NULL); tokc.d = (double)ld;
#else #else
tok = TOK_CLDOUBLE; tok = TOK_CLDOUBLE;
tokc.ld = strtold(token_buf, NULL); tokc.ld = ld;
#endif #endif
} else { } else {
tok = TOK_CDOUBLE; tok = TOK_CDOUBLE;
tokc.d = strtod(token_buf, NULL); tokc.d = (double)ld;
}
} }
} else { } else {
unsigned long long n, n1; uint64_t n = 0, n1;
int warn = 1;
int lcount, ucount; int lcount, ucount;
if (b == 10 && c == '0') {
/* integer number */
*q = '\0';
q = token_buf;
if (b == 10 && *q == '0') {
b = 8; b = 8;
q++;
} }
n = 0;
while(1){ while(1){
t = *q++; if (c == '\0')
/* no need for checks except for base 10 / 8 errors */ break;
if (t == '\0') { 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; 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;
/* detect overflow */ if (n < n1 && warn){
/* XXX: this test is not reliable */ tcc_warning("integer constant overflow");
if (n < n1) warn = 0;
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)
@ -2059,7 +1977,7 @@ static void parse_number(const char *p)
lcount = 0; lcount = 0;
ucount = 0; ucount = 0;
for(;;) { for(;;) {
t = toup(ch); t = toup(c);
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");
@ -2074,7 +1992,7 @@ static void parse_number(const char *p)
#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE #if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
} }
#endif #endif
ch = *p++; c = *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");
@ -2083,7 +2001,7 @@ static void parse_number(const char *p)
tok = TOK_CUINT; tok = TOK_CUINT;
else if (tok == TOK_CLLONG) else if (tok == TOK_CLLONG)
tok = TOK_CULLONG; tok = TOK_CULLONG;
ch = *p++; c = *p++;
} else { } else {
break; break;
} }
@ -2093,7 +2011,7 @@ static void parse_number(const char *p)
else else
tokc.ull = n; tokc.ull = n;
} }
if (ch) if (c)
tcc_error("invalid number\n"); tcc_error("invalid number\n");
} }