Display of numbers and character strings
published: 24 May 2019 / updated 1 September 2020
Digital base change
Also applicable on Flash Forth for Arduino
FORTH does not handle just any numbers. The ones you used while trying the previous examples are signed single precision integers. The domain of definition of single precision integers is between minus 32768 and plus 32767. Example:
32767 . \ display 32767 -32768 . \ display -32768 65535 . \ display -1 (on FRTH systems with 16 bits stack)
These numbers can be processed in any numeric base, all bases numbers between 2 and 36 being valid:
255 HEX . DECIMAL \ display FF
You can choose an even larger number base, but the available symbols will come out of the alpha-numeric set [0..9, A..Z] and may become inconsistent. Example:
DECIMAL 255 BASE ! ò 2 + .
will work, but is hardly semantically conceivable.
The current numeric base is controlled by a variable named BASE
and whose
content can be changed. So, to switch to binary, just store
the value 2 in BASE
. Example:
2 BASE !
and type DECIMAL
to return to the decimal numeric base.
Forth has two predefined words to select different digital bases:
DECIMAL
to select the decimal numeric base. It's here numeric base taken by default when starting Forth.HEX
to select the hexadecimal numeric base.
As soon as one of these numerical bases is selected, the literal numbers will be interpreted, displayed or processed in this database. Any number previously entered in a base numeric different from the current numeric base is automatically converted in the current digital base. Example:
DECIMAL \ decimal base 255 \ push 255 on stack HEX \ select hexadecimal base 1+ \ increment 255 to 256 . \ display 100
You can define your own numeric base by defining the appropriate word or
by storing this database in BASE
. Example:
: BINARY ( ---) \ select binary base 2 BASE ! ; DECIMAL 255 BINARY . \ display 11111111
The contents of BASE
can be stacked like the contents of any
what other variable:
VARIABLE PUT_BASE \ PUT_BASE variable definition BASE @ PUT_BASE ! \ BASE content storage in PUT_BASE HEX FF 10 + . \ display 10F PUT_BASE @ BASE ! \ restore BASE with contents of PUT_BASE
In a "colon" definition, the content of BASE
can pass
by the return stack:
: OPERATION ( ---) BASE @ >R \ store BASE on return stack HEX FF 10 + . \ operation of the previous example R> BASE ! ; \ restore initial value of BASE
WARNING: the words >R
and R>
cannot be used in interpreted mode.
You can only use these words in a definition that will be compiled.
Definition of new display formats
Also applicable on Flash Forth for Arduino
Forth has primitives allowing to adapt the display of a number to a any format. These primitives only deal with double precision numbers:
<#
start a format definition sequence#
insert a digit in a format definition sequence#S
is equivalent to a succession of#
HOLD
inserts a character in a format definition#>
completes a format definition and leaves on the stack the address and length of the string containing the number to display
These words can only be used within a definition. Example, either to display a number expressing an amount expressed in francs with the comma as the decimal separator:
: EUROS ( ud ---)
<# # # ASCII , HOLD #S #>
TYPE ." EUR " ;
Execution examples:
0.35 EUROS \ display 0,35 EUR 35.75 EUROS \ display 35,75 EUR 10.15 35.75 D+ EUROS \ display 45,90 EUR
The definition of EUROS
does not take into account the sign of the result, nor the
position of the decimal point. If you type:
35. EUROS \ you will have 0.35 EUR on display
In the definition of EUROS
, the word <#
begins the format definition sequence
display; the two words #
place the digits of units and tens
in the character string; ASCII , HOLD
place the character, (comma)
after the two digits on the right, the word #S
completes the format
display with non-zero digits after "," the word #>
closes the
format definition and stack the address and length of the string
containing the digits of the number to display; the word TYPE
displays this
string.
At runtime, a display format sequence deals exclusively with signed or unsigned double precision integers. The concatenation of different elements of the chain is done from right to left, i.e. starting with the least significant digits.
Number processing by display format sequence is performed according to the current digital base. The digital base can be changed between two digits.
Here is a more complex example demonstrating the compactness of FORTH. It's about write a program converting any number of seconds in the format HH: MM: SS:
: :00 ( ---) DECIMAL # \ insert digit unit in decimal 6 BASE ! \ base 6 selection # \ ten digit insertion ASCII : HOLD \ character : insertion DECIMAL ; \ return to decimal base : HMS ( ud ---) \ displays number seconds format HH:MM:SS <# :00 :00 #S #> TYPE SPACE ;
Execution examples:
59. HMS \ display 0:00:59 60. HMS \ display 0:01:00 4500. HMS \ display 1:15:00
Explanation: the seconds and minutes display system is
called the sexagesimal system. The 'units' are expressed in the base
numeric decimal, 'tens' are expressed in base six.
The word :00
defined previously manages the conversion of
'units' and 'tens' in these two bases for formatting
digits corresponding to seconds and minutes. For the hours,
the digits are all decimal.
Another example, either to define a program converting an integer simple decimal precision in binary and displaying it as bbbb bbbb bbbb bbbb:
: FOUR-DIGITS ( ---) # # # # 32 HOLD ; : AFB ( d ---) \ format 4 digits and a space BASE @ >R \ Current database backup 2 BASE ! \ Binary digital base selection <# 4 0 DO \ Format Loop FOUR-DIGITS LOOP #> TYPE SPACE \ Binary display R> BASE ! ; \ Initial digital base restoration
Example of execution:
DECIMAL 12. AFB \ display 0000 0000 0000 0110 HEX 3FC5. AFB \ display 0011 1111 1100 0101
Another example, or to create a telephone diary where you associate a patronymic one or more telephone numbers. We define a word by patronymic:
: .## ( ---) # # ASCII . HOLD ; : .TEL ( d ---) CR <# .## .## .## .## .## #> TYPE CR BYE ; : DUGENOU ( ---) .0618051254 .TEL ;
This diary, which can be compiled from a source file, is easily editable, and although the names are not sorted, the search there is extremely fast.
Display of characters and character strings
The display of a character is achieved by the word EMIT
:
65 EMIT \ display A
Displayable characters are in the range 32..255. The codes between 0 and 31 will also be displayed, subject to certain characters executed as control codes. Here is a definition displaying the entire character set of the ASCII table:
: ASCII-SET ( ---) DARK 256 32 DO I 3 .R SPACE \ display character code I EMIT 2 SPACES \ character poster #OUT @ 77 = IF CR THEN LOOP ;
Running ASCII-SET
displays ASCII codes and characters
whose code is between 32 and 255. To display the equivalent table
with the ASCII codes in hexadecimal, type HEX ASCII-SET
.
Character strings are displayed in various ways. The first one, usable in compilation only, displays a character string delimited by the character "(quotation mark):
: TITLE ." GENERAL MENU" ;
TITRE \ display GENERAL MENU
The string is separated from the word ."
by at least one space character.
A character string can also be compiled by the word S"
and delimited by the character "(quotation mark):
: LINE1 ( --- adr len)
S" D..Data logging" ;
Executing LINE1
drops the address and
the length of the string compiled in the definition. The display is made
by the word TYPE
:
LINE1 TYPE \ display D..Data logging
At the end of the display of a character string, the newline must be caused if desired:
LINE1 TYPE \ display D..Data logging CR TITLE CR CR LINE1 TYPE CR \ display \ GENERAL MENU \ \ D..Data logging
One or more spaces can be added at the start or end of the display of a alphanumeric string:
SPACE \ displays a space character 10 SPACES \ displays 10 characters space