summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2007-10-22 17:34:10 -0700
committerH. Peter Anvin <hpa@zytor.com>2007-10-22 17:34:10 -0700
commitc65a2f634b8ca75cceeb79a9afbc381a7ae0362f (patch)
tree8da0be6ba7427bdb9aa3298884bce74c2cef30a9
parentbea0bbb62c9947421bc0fddcd2b58a40435e2181 (diff)
downloadnasm-c65a2f634b8ca75cceeb79a9afbc381a7ae0362f.tar.gz
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.
-rw-r--r--float.c78
-rw-r--r--stdscan.c2
-rw-r--r--test/radix.asm19
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