strtod
also fixed comparing strings
This commit is contained in:
parent
f7c3154b8a
commit
1ea9d85e3f
4 changed files with 193 additions and 27 deletions
20
05/codegen.b
20
05/codegen.b
|
@ -1515,6 +1515,8 @@ function comparison_type
|
||||||
argument expr
|
argument expr
|
||||||
local type1
|
local type1
|
||||||
local type2
|
local type2
|
||||||
|
local t1
|
||||||
|
local t2
|
||||||
expr += 8
|
expr += 8
|
||||||
|
|
||||||
type1 = expr + 4
|
type1 = expr + 4
|
||||||
|
@ -1523,17 +1525,19 @@ function comparison_type
|
||||||
type2 = expr + 4
|
type2 = expr + 4
|
||||||
type2 = *4type2
|
type2 = *4type2
|
||||||
|
|
||||||
type1 += types
|
t1 = types + type1
|
||||||
type1 = *1type1
|
t1 = *1t1
|
||||||
type2 += types
|
t2 = types + type2
|
||||||
type2 = *1type2
|
t2 = *1t2
|
||||||
|
|
||||||
; do float comparisons as double comparisons to make things simpler
|
; do float comparisons as double comparisons to make things simpler
|
||||||
if type1 == TYPE_FLOAT goto return_type_double
|
if t1 == TYPE_FLOAT goto return_type_double
|
||||||
if type2 == TYPE_FLOAT goto return_type_double
|
if t2 == TYPE_FLOAT goto return_type_double
|
||||||
|
|
||||||
if type1 == TYPE_POINTER goto return_type_unsigned_long
|
if t1 == TYPE_POINTER goto return_type_unsigned_long
|
||||||
if type2 == TYPE_POINTER goto return_type_unsigned_long
|
if t2 == TYPE_POINTER goto return_type_unsigned_long
|
||||||
|
if t1 == TYPE_ARRAY goto return_type_unsigned_long ; type1 decays to pointer
|
||||||
|
if t2 == TYPE_ARRAY goto return_type_unsigned_long ; type2 decays to pointer
|
||||||
return expr_binary_type_usual_conversions(statement, type1, type2)
|
return expr_binary_type_usual_conversions(statement, type1, type2)
|
||||||
|
|
||||||
; is this comparison expression a comparison between unsigned integers or floats?
|
; is this comparison expression a comparison between unsigned integers or floats?
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
char s[] = " -0XAh.\n";
|
char *s = "1.35984534e135-e12hello";
|
||||||
char *end;
|
char *end;
|
||||||
errno = 0;
|
_Float f = _powers_of_10[-307];
|
||||||
printf("%ld\n", strtol(s, &end, 0));
|
printf("%.15g\n",strtod(s, &end));
|
||||||
printf("%d:%s",errno,end);
|
printf("%s\n",end);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2775,7 +2775,6 @@ function parse_expression
|
||||||
if c == EXPRESSION_LT goto type_int
|
if c == EXPRESSION_LT goto type_int
|
||||||
if c == EXPRESSION_GT goto type_int
|
if c == EXPRESSION_GT goto type_int
|
||||||
if c == EXPRESSION_COMMA goto type_binary_right
|
if c == EXPRESSION_COMMA goto type_binary_right
|
||||||
if c == EXPRESSION_EQ goto type_binary_left
|
|
||||||
if c == EXPRESSION_ASSIGN goto type_binary_left
|
if c == EXPRESSION_ASSIGN goto type_binary_left
|
||||||
if c == EXPRESSION_ASSIGN_ADD goto type_binary_left
|
if c == EXPRESSION_ASSIGN_ADD goto type_binary_left
|
||||||
if c == EXPRESSION_ASSIGN_SUB goto type_binary_left
|
if c == EXPRESSION_ASSIGN_SUB goto type_binary_left
|
||||||
|
|
191
05/stdc_common.h
191
05/stdc_common.h
|
@ -1,11 +1,6 @@
|
||||||
#ifndef _STDC_COMMON_H
|
#ifndef _STDC_COMMON_H
|
||||||
#define _STDC_COMMON_H
|
#define _STDC_COMMON_H
|
||||||
|
|
||||||
#ifdef _STDLIB_DEBUG
|
|
||||||
int printf(char *);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define signed
|
#define signed
|
||||||
#define volatile
|
#define volatile
|
||||||
#define register
|
#define register
|
||||||
|
@ -105,6 +100,24 @@ void _Exit(int status) {
|
||||||
return __syscall(60, status, 0, 0, 0, 0, 0);
|
return __syscall(60, status, 0, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int kill(int pid, int sig) {
|
||||||
|
return __syscall(62, pid, sig, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getpid(void) {
|
||||||
|
return __syscall(39, 0, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SIGABRT 6
|
||||||
|
#define SIGFPE 8
|
||||||
|
#define SIGILL 4
|
||||||
|
#define SIGINT 2
|
||||||
|
#define SIGSEGV 11
|
||||||
|
#define SIGTERM 15
|
||||||
|
void abort(void) {
|
||||||
|
kill(getpid(), SIGABRT);
|
||||||
|
}
|
||||||
|
|
||||||
typedef long time_t;
|
typedef long time_t;
|
||||||
|
|
||||||
struct timespec {
|
struct timespec {
|
||||||
|
@ -126,8 +139,29 @@ int access(const char *pathname, int mode) {
|
||||||
return __syscall(21, pathname, mode, 0, 0, 0, 0);
|
return __syscall(21, pathname, mode, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int fd;
|
||||||
|
unsigned char eof;
|
||||||
|
unsigned char err;
|
||||||
|
} FILE;
|
||||||
|
|
||||||
int errno;
|
int errno;
|
||||||
|
int printf(char *, ...);
|
||||||
|
int fprintf(FILE *, char *, ...); // needed now for assert()
|
||||||
|
|
||||||
|
FILE _stdin = {0}, *stdin;
|
||||||
|
FILE _stdout = {1}, *stdout;
|
||||||
|
FILE _stderr = {2}, *stderr;
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define assert(x) ((void)0)
|
||||||
|
#else
|
||||||
|
int __assert_failed(const char *file, int line, const char *expr) {
|
||||||
|
fprintf(stderr, "Assertion failed at %s:%d: %s\n", file, line, expr);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
#define assert(x) (void)((x) || __assert_failed(__FILE__, __LINE__, #x))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define EIO 5
|
#define EIO 5
|
||||||
#define EDOM 33
|
#define EDOM 33
|
||||||
|
@ -223,7 +257,7 @@ unsigned long strtoul(const char *nptr, char **endptr, int base) {
|
||||||
value = newvalue;
|
value = newvalue;
|
||||||
++nptr;
|
++nptr;
|
||||||
}
|
}
|
||||||
*endptr = nptr;
|
if (endptr) *endptr = nptr;
|
||||||
if (overflow) {
|
if (overflow) {
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
return ULONG_MAX;
|
return ULONG_MAX;
|
||||||
|
@ -255,22 +289,151 @@ long strtol(const char *nptr, char **endptr, int base) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
long _strtol_clamped(const char *nptr, char **endptr, int base, int min, int max) {
|
||||||
int fd;
|
long l = strtol(nptr, endptr, base);
|
||||||
unsigned char eof;
|
if (l < min) return min;
|
||||||
unsigned char err;
|
if (l > max) return max;
|
||||||
} FILE;
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _NPOW10 310
|
||||||
|
#define _INFINITY 1e1000
|
||||||
|
// non-negative floating-point number with more precision than a double
|
||||||
|
// its value is equal to fraction * 2^exponent
|
||||||
|
typedef struct {
|
||||||
|
unsigned long fraction;
|
||||||
|
int exponent;
|
||||||
|
} _Float;
|
||||||
|
|
||||||
|
// ensure that f->fraction >= 2^64 / 2
|
||||||
|
static void _normalize_float(_Float *f) {
|
||||||
|
if (!f->fraction) return;
|
||||||
|
while (f->fraction < 0x8000000000000000) {
|
||||||
|
f->exponent -= 1;
|
||||||
|
f->fraction <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static double _Float_to_double(_Float f) {
|
||||||
|
unsigned long dbl_fraction;
|
||||||
|
int dbl_exponent;
|
||||||
|
unsigned long dbl_value;
|
||||||
|
if (f.fraction == 0) return 0;
|
||||||
|
_normalize_float(&f);
|
||||||
|
f.fraction &= 0x7fffffffffffffff; // remove the "1." in 1.01101110111... to get 63-bit significand
|
||||||
|
dbl_fraction = (f.fraction + 0x3ff) >> 11;
|
||||||
|
dbl_exponent = f.exponent + 63;
|
||||||
|
if (dbl_exponent < -1022) return 0;
|
||||||
|
if (dbl_exponent > 1023) return _INFINITY;
|
||||||
|
dbl_exponent += 1023;
|
||||||
|
dbl_value = (unsigned long)dbl_exponent << 52 | dbl_fraction;
|
||||||
|
return *(double *)&dbl_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Float _powers_of_10_dat[2*_NPOW10+1];
|
||||||
|
static _Float *_powers_of_10;
|
||||||
|
static _Float _Float_ZERO = {0, 1};
|
||||||
|
static _Float _Float_INFINITY = {0x8000000000000000, 100000};
|
||||||
|
|
||||||
|
|
||||||
|
_Float _int_pow10(int x) {
|
||||||
|
if (x <= -_NPOW10) return _Float_ZERO;
|
||||||
|
if (x >= _NPOW10) return _Float_INFINITY;
|
||||||
|
return _powers_of_10[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
double strtod(const char *nptr, char **endptr) {
|
||||||
|
const char *flt, *dot, *p, *number_end;
|
||||||
|
double sign = 1;
|
||||||
|
int exponent = 0;
|
||||||
|
while (isspace(*nptr)) ++nptr;
|
||||||
|
|
||||||
|
flt = nptr; // start of float
|
||||||
|
if (*flt == '+') ++flt;
|
||||||
|
else if (*flt == '-') sign = -1, ++flt;
|
||||||
|
|
||||||
|
if (*flt != '.' && (*flt < '0' || *flt > '9')) {
|
||||||
|
// this isn't a float
|
||||||
|
*endptr = nptr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the decimal point, if any
|
||||||
|
dot = flt;
|
||||||
|
while (*dot >= '0' && *dot <= '9') ++dot;
|
||||||
|
|
||||||
|
nptr = dot + (*dot == '.');
|
||||||
|
// skip digits after the dot
|
||||||
|
while (*nptr >= '0' && *nptr <= '9') ++nptr;
|
||||||
|
number_end = nptr;
|
||||||
|
|
||||||
|
if (*nptr == 'e') {
|
||||||
|
++nptr;
|
||||||
|
exponent = 1;
|
||||||
|
if (*nptr == '+') ++nptr;
|
||||||
|
else if (*nptr == '-') ++nptr, exponent = -1;
|
||||||
|
exponent *= _strtol_clamped(nptr, &nptr, 10, -10000, 10000); // use _strtol_clamped to prevent problems with -LONG_MIN
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct the value using the Kahan summation algorithm (https://en.wikipedia.org/wiki/Kahan_summation_algorithm)
|
||||||
|
double sum = 0;
|
||||||
|
double c = 0;
|
||||||
|
for (p = flt; p < number_end; ++p) {
|
||||||
|
if (*p == '.') continue;
|
||||||
|
int n = *p - '0';
|
||||||
|
assert(n >= 0 && n <= 9);
|
||||||
|
int pow10 = dot - p;
|
||||||
|
pow10 -= pow10 > 0;
|
||||||
|
pow10 += exponent;
|
||||||
|
_Float f_val = _int_pow10(pow10);
|
||||||
|
f_val.fraction >>= 4;
|
||||||
|
f_val.exponent += 4;
|
||||||
|
f_val.fraction *= n;
|
||||||
|
double value = _Float_to_double(f_val);
|
||||||
|
if (value == _INFINITY || sum == _INFINITY) {
|
||||||
|
sum = _INFINITY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
double y = value - c;
|
||||||
|
double t = sum + y;
|
||||||
|
c = (t - sum) - y;
|
||||||
|
sum = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endptr) *endptr = nptr;
|
||||||
|
return sum * sign;
|
||||||
|
}
|
||||||
|
|
||||||
FILE _stdin = {0}, *stdin;
|
|
||||||
FILE _stdout = {1}, *stdout;
|
|
||||||
FILE _stderr = {2}, *stderr;
|
|
||||||
|
|
||||||
int main();
|
int main();
|
||||||
|
|
||||||
int _main(int argc, char **argv) {
|
int _main(int argc, char **argv) {
|
||||||
|
int i;
|
||||||
|
_Float p = {1, 0};
|
||||||
|
|
||||||
stdin = &_stdin;
|
stdin = &_stdin;
|
||||||
stdout = &_stdout;
|
stdout = &_stdout;
|
||||||
stderr = &_stderr;
|
stderr = &_stderr;
|
||||||
|
|
||||||
|
// initialize powers of 10
|
||||||
|
_powers_of_10 = _powers_of_10_dat + _NPOW10;
|
||||||
|
for (i = 0; i < _NPOW10; ++i) {
|
||||||
|
_normalize_float(&p);
|
||||||
|
_powers_of_10[i] = p;
|
||||||
|
p.exponent += 4;
|
||||||
|
p.fraction >>= 4;
|
||||||
|
p.fraction *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.fraction = 1;
|
||||||
|
p.exponent = 0;
|
||||||
|
for (i = 0; i > -_NPOW10; --i) {
|
||||||
|
_normalize_float(&p);
|
||||||
|
_powers_of_10[i] = p;
|
||||||
|
p.fraction /= 5;
|
||||||
|
p.exponent -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
return main(argc, argv);
|
return main(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue