If you are a programmer, you know how important this subject is to you. Sometimes, you want to print numbers in octal, binary or hex. 4tH can do that too. Let's take the previous program and alter it a bit:
." Enter a number: " \ write prompt refill drop \ enter string bl word \ parse string number dup \ convert to a number (error) = \ test for valid number if \ if not valid ." You didn't enter a valid number!" drop cr else \ print if valid hex ." The number was: " . cr then
We added the word 'HEX' just before printing the number. Now the number will be printed in hexadecimal. 4tH has a number of words that can change the radix, like 'DECIMAL' and 'OCTAL'. They work in the same way as 'HEX'.
4tH always starts in decimal. After that you are responsible. Note that all radix control follows the flow of the program. If you call a self- defined word that alters the radix all subsequent conversion is done too in that radix:
: .hex hex . ; \ print a number in hex ." Enter a number: " \ write prompt refill drop \ enter string bl word \ parse string number dup \ convert to a number (error) = \ test for valid number if \ if not valid ." You didn't enter a valid number!" drop cr else \ print if valid ." The number was: " .hex cr then
In this example not only that single number is printed in hex, but also all subsequent numbers will be printed in hex! A better version of the ".HEX" definition would be:
: .hex hex . decimal ;
Since that one resets the radix back to decimal. Words like 'HEX' do not only control the output of a number, but the input of numbers is also affected:
." Enter a number: " \ write prompt refill drop \ enter string bl word \ parse string hex \ convert hexadecimal number dup \ convert to a number (error) = \ test for valid number if \ if not valid ." You didn't enter a valid number!" drop cr else \ print if valid dup ." The number was: " decimal . ." decimal" cr ." The number was: " hex . ." hex" cr then
'NUMBER' will now also accept hexadecimal numbers. If the number is not a valid hexadecimal number, it will return '(ERROR)'. You probably know there is more to radix control than 'OCTAL', 'HEX' and 'DECIMAL'. No, we have not forgotten them. In fact, you can choose any radix between 2 and 36. This slightly modified program will only accept binary numbers:
: binary 2 base ! ; ." Enter a number: " \ write prompt refill drop \ enter string bl word \ parse string binary \ convert hexadecimal number dup \ convert to a number (error) = \ test for valid number if \ if not valid ." You didn't enter a valid number!" drop cr else \ print if valid dup \ both decimal and hex ." The number was: " decimal . ." decimal" cr ." The number was: " hex . ." hex" cr then
'BASE' is a predefined variable that enables you to select any radix between 2 and 36. This makes 4tH very flexible. However, this won't work:
hex 02B decimal . cr
4tH will try to compile "02B", but since it isn't a word or a valid decimal number, it will fail. Words like 'HEX' and the 'BASE' variable work only at run-time, not at compile-time! Isn't there a way to compile non-decimal numbers?
Sure, there is, although it is not that flexible. There are four words that control the interpretation of numbers at compile-time:
They work fundamentally different than their run-time equivalents. First, they only work at compile-time. Second, they are interpreted sequentially and do not follow the flow of the program. Let's take a look at these two programs:
[binary] 101 . cr [octal] 101 . cr [decimal] 101 . cr [hex] 101 . cr
This will print the decimal numbers "5", "65", "101" and "257", since each one of them is compiled with a specific radix.
: binary 2 base ! ; binary 101 . cr octal 101 . cr decimal 101 . cr hex 101 . cr
Now the decimal number "101" is printed in four different radixes, since at compile-time the radix was set to decimal (which is the default). Now take a look at this program:
: do_binary [binary] ; : do_decimal [decimal] ; do_binary 101 decimal . cr do_decimal 101 decimal . cr
The program will print "101" two times! Haven't we selected binary at compile-time? No, both '[BINARY]' and '[DECIMAL]' are interpreted sequentially!
When '[BINARY]' is encountered at the first time, it will set the radix at compile-time to binary. When '[DECIMAL]' is encountered in the second line, it will set the radix to decimal. When the third line it compiled, the radix is still set to decimal. If you want to make this program work, try this:
[binary] 101 decimal . cr [decimal] 101 decimal . cr
When the first line is encountered, it sets the radix (at compile-time) to binary. So the number "101" at line two is compiled as a binary number. 'DECIMAL' will just be compiled. It will only influence the radix at run-time. The third line sets the radix at compile-time to decimal. So the number "101" at line four is compiled as a decimal number.
Since the run-time of 4tH starts up in decimal, both occurrences of 'DECIMAL' have little value. We can even eliminate 'DECIMAL' from the program altogether without affecting the result:
[binary] 101 . cr [decimal] 101 . cr
Note that both the compile-time radix control words and the run-time radix control words stay in effect until they are superseded by others:
[binary] \ compile-time binary 101 \ first binary number 1011 \ second binary number [decimal] \ compile-time decimal 5 \ decimal 5 do \ set run-time radix i base ! \ to loop-index dup . cr \ print number loop drop \ clean stack