From c65a2f634b8ca75cceeb79a9afbc381a7ae0362f Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 22 Oct 2007 17:34:10 -0700 Subject: [PATCH] Support binary and octal floating-point For consistency, support binary and octal floating-point, and accept a "0d" or "0t" prefix for decimal floating-point. However, we do not accept a binary exponent (p) for a decimal mantissa, or vice versa. --- float.c | 78 ++++++++++++++++++++++++++++++++++++++++------------------ stdscan.c | 2 +- test/radix.asm | 19 +++++++++++++- 3 files changed, 73 insertions(+), 26 deletions(-) diff --git a/float.c b/float.c index a2df323d..7e99f96c 100644 --- a/float.c +++ b/float.c @@ -424,29 +424,33 @@ static bool ieee_round(int sign, uint16_t * mant, int32_t i) return false; } -static int hexval(char c) +/* Returns a value >= 16 if not a valid hex digit */ +static unsigned int hexval(char c) { - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'a' && c <= 'f') - return c - 'a' + 10; + unsigned int v = (unsigned char) c; + + if (v >= '0' && v <= '9') + return v - '0'; else - return c - 'A' + 10; + return (v|0x20) - 'a' + 10; } -static bool ieee_flconvert_hex(const char *string, uint16_t * mant, - int32_t * exponent) +/* Handle floating-point numbers with radix 2^bits and binary exponent */ +static bool ieee_flconvert_bin(const char *string, int bits, + uint16_t * mant, int32_t * exponent) { static const int log2tbl[16] = { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; uint16_t mult[MANT_WORDS + 1], *mp; int ms; int32_t twopwr; - int seendot, seendigit; + bool seendot, seendigit; unsigned char c; + int radix = 1 << bits; + unsigned int v; twopwr = 0; - seendot = seendigit = 0; + seendot = seendigit = false; ms = 0; mp = NULL; @@ -461,17 +465,15 @@ static bool ieee_flconvert_hex(const char *string, uint16_t * mant, "too many periods in floating-point constant"); return false; } - } else if (isxdigit(c)) { - int v = hexval(c); - + } else if ((v = hexval(c)) < (unsigned int)radix) { if (!seendigit && v) { int l = log2tbl[v]; seendigit = 1; mp = mult; - ms = 15 - l; + ms = 15-l; - twopwr = seendot ? twopwr - 4 + l : l - 3; + twopwr = seendot ? twopwr-bits+l : l+1-bits; } if (seendigit) { @@ -483,13 +485,13 @@ static bool ieee_flconvert_hex(const char *string, uint16_t * mant, ms += 16; } *mp |= v << ms; - ms -= 4; + ms -= bits; if (!seendot) - twopwr += 4; + twopwr += bits; } else { if (seendot) - twopwr -= 4; + twopwr -= bits; } } else if (c == 'p' || c == 'P') { int32_t e; @@ -656,13 +658,41 @@ static int to_float(const char *str, int sign, uint8_t * result, break; } } else { - if (str[0] == '0' && - (str[1] == 'x' || str[1] == 'X' || str[1] == 'h' || str[1] == 'H')) - ok = ieee_flconvert_hex(str + 2, mant, &exponent); - else if (str[0] == '$') - ok = ieee_flconvert_hex(str + 1, mant, &exponent); - else + if (str[0] == '0') { + switch (str[1]) { + case 'x': case 'X': + case 'h': case 'H': + ok = ieee_flconvert_bin(str+2, 4, mant, &exponent); + break; + case 'o': case 'O': + case 'q': case 'Q': + ok = ieee_flconvert_bin(str+2, 3, mant, &exponent); + break; + case 'b': case 'B': + case 'y': case 'Y': + ok = ieee_flconvert_bin(str+2, 1, mant, &exponent); + break; + case 'd': case 'D': + case 't': case 'T': + ok = ieee_flconvert(str+2, mant, &exponent); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '\0': + /* Leading zero was just a zero */ + ok = ieee_flconvert(str, mant, &exponent); + break; + default: + error(ERR_NONFATAL, + "floating-point constant: invalid radix `%c'", str[1]); + ok = false; + break; + } + } else if (str[0] == '$') { + ok = ieee_flconvert_bin(str+1, 4, mant, &exponent); + } else { ok = ieee_flconvert(str, mant, &exponent); + } if (!ok) { type = FL_QNAN; diff --git a/stdscan.c b/stdscan.c index dda4e0a3..8295054a 100644 --- a/stdscan.c +++ b/stdscan.c @@ -141,7 +141,7 @@ int stdscan(void *private_data, struct tokenval *tv) } } else if (c == 'H' || c == 'h' || c == 'X' || c == 'x') { is_hex = true; - } else if (is_hex && (c == 'P' || c == 'p')) { + } else if (c == 'P' || c == 'p') { is_float = true; if (*stdscan_bufptr == '+' || *stdscan_bufptr == '-') stdscan_bufptr++; diff --git a/test/radix.asm b/test/radix.asm index 35dbceef..c08b5500 100644 --- a/test/radix.asm +++ b/test/radix.asm @@ -1,3 +1,5 @@ + ;; Integer constants... + dd 1010_0101 ; Decimal dd 01010_0101 ; Decimal (*not* octal!) dd 0d1010_0101 ; Decimal @@ -20,4 +22,19 @@ dd 1010_0101h ; Hex dd 1010_0101x ; Hex dd $1010_0101 ; Hex - \ No newline at end of file + + ;; Floating-point constants + ;; All of these should output B4A21147 + dd 3.7282705e+4 ; Decimal + dd 00003.7282705e+4 ; Decimal + dd 0d3.7282705e+4 ; Decimal + dd 0t3.7282705e+4 ; Decimal + + dd 0x1.23456789p+15 ; Hex + dd 0h1.23456789p+15 ; Hex + + dd 0o1.10642547422p+15 ; Octal + dd 0q1.10642547422p+15 ; Octal + + dd 0b1.0010_0011_0100_0101_0110_0111_1000_1001p+15 ; Binary + dd 0y1.0010_0011_0100_0101_0110_0111_1000_1001p+15 ; Binary -- 2.11.4.GIT