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

358
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=='.'){
goto float_frac_parse; --p;
} else if (t == '0') { goto float_frac_parse;
if (ch == 'x' || ch == 'X') { }
q--; if(c == '0'){
ch = *p++; if (t == 'x' || t == 'X') {
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{
/* parse all digits. cannot check octal numbers at this stage --p;
because of floating point constants */ }
while (1) { }else
if (ch >= 'a' && ch <= 'f') --p;
t = ch - 'a' + 10; if(strchr(p , '.') || (b == 10 && (strchr(p,'e') || strchr(p,'E'))) ||
else if (ch >= 'A' && ch <= 'F') ((b == 2 || b == 16)&& (strchr(p,'p') || strchr(p,'P')))){
t = ch - 'A' + 10; long double ld, sh, fb;
else if (isnum(ch)) int exp;
t = ch - '0'; /* NOTE: strtox should support that for hexa numbers, but
else non ISOC99 libcs do not support it, so we prefer to do
break; it by hand */
if (t >= b) /* hexadecimal or binary floats */
break; /* XXX: handle overflows */
if (q >= token_buf + STRING_MAX_SIZE) { float_frac_parse:
num_too_long: fb = 1.0L/b;
tcc_error("number too long"); sh = b;
} ld = 0.0;
*q++ = ch;
ch = *p++; while(1){
} if (c == '\0')
if (ch == '.' || break;
((ch == 'e' || ch == 'E') && b == 10) || if (c >= 'a' && c <= 'f')
((ch == 'p' || ch == 'P') && (b == 16 || b == 2))) { t = c - 'a' + 10;
if (b != 10) { else if (c >= 'A' && c <= 'F')
/* NOTE: strtox should support that for hexa numbers, but t = c - 'A' + 10;
non ISOC99 libcs do not support it, so we prefer to do else if(isnum(c))
it by hand */ t = c - '0';
/* hexadecimal or binary floats */ else
/* XXX: handle overflows */ break;
*q = '\0'; if (t >= b)
if (b == 16) tcc_error("invalid digit");
shift = 4; ld = ld * b + t;
else c = *p++;
shift = 2; }
bn_zero(bn); if (c == '.'){
q = token_buf; c = *p++;
while (1) { sh = fb;
t = *q++; while (1){
if (t == '\0') { if (c == '\0')
break; break;
} else if (t >= 'a') { if (c >= 'a' && c <= 'f')
t = t - 'a' + 10; t = c - 'a' + 10;
} else if (t >= 'A') { else if (c >= 'A' && c <= 'F')
t = t - 'A' + 10; t = c - 'A' + 10;
} else { else if (isnum(c))
t = t - '0'; t =c - '0';
} else
bn_lshift(bn, shift, t); break;
} if (t >= b){
frac_bits = 0; if(b == 10 && (c == 'e' || c == 'E' || c == 'f' || c == 'F'))
if (ch == '.') { break;
ch = *p++; tcc_error("invalid digit");
while (1) { }
t = ch; ld += sh*t;
if (t >= 'a' && t <= 'f') { sh*=fb;
t = t - 'a' + 10; c = *p++;
} else if (t >= 'A' && t <= 'F') { }
t = t - 'A' + 10; }
} else if (t >= '0' && t <= '9') { if ((b == 16 || b == 2) && c != 'p' && c != 'P')
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"); expect("exponent");
ch = *p++; if(((c == 'e' || c == 'E') && b == 10) ||
s = 1; ((c == 'p' || c == 'P') && (b == 16 || b == 2))){
exp_val = 0; c = *p++;
if (ch == '+') { if(c == '+' || c == '-'){
ch = *p++; if (c == '-')
} else if (ch == '-') { sh = fb;
s = -1; 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;
exp_val = exp_val * 10 + ch - '0'; do{
ch = *p++; exp = exp * 10 + c - '0';
} c = *p++;
exp_val = exp_val * s; }while(isnum(c));
while (exp != 0){
/* now we can generate the number */ if (exp & 1)
/* XXX: should patch directly float number */ ld *= sh;
d = (double)bn[1] * 4294967296.0 + (double)bn[0]; exp >>= 1;
d = ldexp(d, exp_val - frac_bits); sh *= sh;
t = toup(ch); }
if (t == 'F') { }
ch = *p++; t = toup(c);
tok = TOK_CFLOAT; if (t == 'F') {
/* float : should handle overflow */ c = *p++;
tokc.f = (float)d; tok = TOK_CFLOAT;
} else if (t == 'L') { tokc.f = (float)ld;
ch = *p++; } else if (t == 'L') {
c = *p++;
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
tok = TOK_CDOUBLE; tok = TOK_CDOUBLE;
tokc.d = d; tokc.d = (double)ld;
#else #else
tok = TOK_CLDOUBLE; tok = TOK_CLDOUBLE;
/* XXX: not large enough */ tokc.ld = ld;
tokc.ld = (long double)d;
#endif #endif
} else { } else {
tok = TOK_CDOUBLE; tok = TOK_CDOUBLE;
tokc.d = d; tokc.d = (double)ld;
} }
} else {
/* decimal floats */
if (ch == '.') {
if (q >= token_buf + STRING_MAX_SIZE)
goto num_too_long;
*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 { } 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) { 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;
break; else if (c >= 'A' && c <= 'F')
} else if (t >= 'a') { t = c - 'A' + 10;
t = t - 'a' + 10; else if(isnum(c))
} else if (t >= 'A') { t = c - '0';
t = t - 'A' + 10; else
} else { break;
t = t - '0'; if (t >= b)
if (t >= b) tcc_error("invalid digit");
tcc_error("invalid digit"); n1 = n;
} n = n * b + t;
n1 = n; if (n < n1 && warn){
n = n * b + t; tcc_warning("integer constant overflow");
/* detect overflow */ warn = 0;
/* XXX: this test is not reliable */ }
if (n < n1) c = *p++;
tcc_error("integer constant overflow"); }
}
/* 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");
} }