A standard RETRO image only supports decimal base numbers. This shows a way to add support for multiple bases. (Borrowing from KipIngram and zy]x[yz in #forth irc channel).
Once loaded, numbers can be used like:
#[-][decimal radix:]digits
Examples:
#100
#10:100
#16:FF
#2:1010101
{{
This begins with some data structures. First, a string with all of the allowed symbols. This should be extended if you need bases higher than 16.
'0123456789ABCDEF 'DIGITS s:const
Next, a variable to track the base.
'Base var
Conversion to a numeric value is pretty easy.
-
set a variable to hold the numeric value to zero (as a stating point)
-
check to see if the first character is - for negative, set a modifier
-
see if there is a base
- yes: set
Base
to this - no: set
Base
to 10
- yes: set
-
for each character in the string:
- convert to a numeric value (in this case, it's the index in the DIGITS string)
- Multiply the last value of the number accumulator by the base
- Add the converted value
- Store the result in the number accumulator
-
Multiply the final number by the modifier
:check-sign (s-ns)
dup fetch $- eq? [ #-1 swap n:inc ] [ #1 swap ] choose ;
:determine-base (s-s)
dup $: s:contains-char?
[ $: s:split s:to-number !Base n:inc ]
[ #10 !Base ] choose ;
:convert (nc-N)
&DIGITS swap s:index-of swap @Base * + ;
---reveal---
I am leaving s:to-number
exposed as it'll be beneficial to keep consistent with the #
prefix.
:s:to-number (s-n)
check-sign determine-base #0 swap
[ convert ] s:for-each * ;
Last, use the above to implement a new #
prefix for parsing numbers.
:prefix:# (s-n) s:to-number class:data ; immediate
}}
And a few tests.
#255
#16:FF
#2:1111