summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--05/main.b6
-rw-r--r--05/tokenize.b55
-rw-r--r--05/util.b23
3 files changed, 82 insertions, 2 deletions
diff --git a/05/main.b b/05/main.b
index b500150..b247584 100644
--- a/05/main.b
+++ b/05/main.b
@@ -152,6 +152,7 @@ function normalize_float
local exponent
significand = *8p_significand
+ if significand == 0 goto normalize_0
exponent = *8p_exponent
:float_reduce_loop
@@ -169,7 +170,10 @@ function normalize_float
*8p_significand = significand
*8p_exponent = exponent
return
-
+ :normalize_0
+ *8p_exponent = 0
+ return
+
function fill_in_powers_of_10
local i
local p
diff --git a/05/tokenize.b b/05/tokenize.b
index 1c197a7..e6bd48e 100644
--- a/05/tokenize.b
+++ b/05/tokenize.b
@@ -122,6 +122,11 @@ function tokenize
local data
local significand
local exponent
+ local pow10
+ local integer
+ local fraction
+ local lower
+ local upper
in = pptokens
:tokenize_loop
@@ -263,8 +268,51 @@ function tokenize
:tokenize_float
significand = 0
exponent = 0
- ; @TODO
+ pow10 = 0
+ integer = strtoi(&in, 10)
+ fraction = 0
+ if *1in != '. goto float_no_fraction
+ in += 1
+ p = in
+ fraction = strtoi(&in, 10)
+ ; e.g. to turn 35 into .35, multiply by 10^-2
+ pow10 = p - in
+ if pow10 < -400 goto bad_float
+ :float_no_fraction
+ ; construct the number integer + fraction*10^pow10
+ ; first, deal with the fractional part
+ p = powers_of_10
+ p += pow10 < 4
+ full_multiply_signed(fraction, *8p, &upper, &lower)
+ ; effectively we want the upper 58 bits of this multiplication
+ significand = lower > 58
+ significand |= upper < 6
+ p += 8
+ significand >= 0 - *8p
+ if integer == 0 goto float_no_integer
+ ; we now have significand / 2^58 = fraction*10^pow10
+ ; now deal with the integer part
+ exponent = leftmost_1bit(integer)
+ significand >= exponent
+ n = 58 - exponent
+ significand += integer < n
+ if *1in != 'e goto float_no_exponent
+
+ :float_no_exponent
+ if significand == 0 goto float_zero
+ ; reduce to 52-bit significant
+ significand >= 6
+ exponent += 6
+ exponent += 51 ; 1001010111... => 1.001010111...
+ n = leftmost_1bit(significand)
+ b = 1 < n
+ significand &= ~b
+ data = significand
+ exponent += 1023 ; float format
+ data |= exponent < 52
+ :float_no_integer
byte 0xcc
+ :float_zero
:tokenize_loop_end
return 0
@@ -293,6 +341,11 @@ function tokenize
:str_bad_token
string Bad token.
byte 0
+ :bad_float
+ compile_error(file, line_number, .str_bad_float)
+ :str_bad_float
+ string Bad floating-point number.
+ byte 0
; return character or escaped character from *p_in, advancing accordingly
; returns -1 on bad character
diff --git a/05/util.b b/05/util.b
index 190c736..51a98da 100644
--- a/05/util.b
+++ b/05/util.b
@@ -477,6 +477,29 @@ function exit
argument status_code
syscall(0x3c, status_code)
+; return index of leftmost bit
+; error on 0
+function leftmost_1bit
+ argument x
+ local i
+ local b
+ if x == 0 goto leftmost1bit_0
+
+ i = 63
+ :leftmost1bit_loop
+ b = 1 < i
+ b &= x
+ if b != 0 goto leftmost1bit_found
+ i -= 1
+ goto leftmost1bit_loop
+ :leftmost1bit_found
+ return i
+ :leftmost1bit_0
+ fputs(2, .str_leftmost1bit_0)
+ exit(1)
+ :str_leftmost1bit_0
+ string 0 passed to leftmost_1bit.
+ byte 0
:return_0
return 0
:return_1