Strings
There are four ways to express strings:
- A list of characters
The expression "fred" is the four bytes 'f', 'r', 'e', and
'd'.
If used to initialize and allocate the space for a variable, four bytes will
be allocated for the variable and the first value will be 'f'.
If used in a function, the four bytes will be pushed onto the data stack
with the 'f' on the top of the data stack.
- Null-terminated (like C)
The expression N"fred" is the four bytes 'f', 'r', 'e', 'd', and
'\0' (the null character).
If used to initialize and allocate the space for a variable, five bytes will
be allocated for the variable and the first value will be 'f'.
If used in a function, the five bytes will be pushed onto the data stack
with the 'f' on the top of the data stack.
- Counted (like Forth)
The expression C"fred" is the five bytes 4, 'f', 'r', 'e', and
'd'.
If used to initialize and allocate the space for a variable, five bytes will
be allocated for the variable and the first value will be 4 and the second
value will be 'f'.
If used in a function, the five bytes will be pushed onto the data stack
with the the number 4 on the top of the data stack and 'f' in the
next-to-top of the data stack.
- Lesser-counted
The expression c"fred" is the five bytes 3, 'f', 'r', 'e', and
'd'.
If used to initialize and allocate the space for a variable, five bytes will
be allocated for the variable and the first value will be 3 and the second
value will be 'f'.
If used in a function, the five bytes will be pushed onto the data stack
with the the number 3 on the top of the data stack and 'f' in the
next-to-top of the data stack.
Examples
A list of characters
If the variable nibble_to_hex is set to the length 16
string "0123456789ABCDEF", then it can be used to convert a
nibble (with a value between 0 and 15 inclusive) to the corresponding hex
character.
The following is a function that converts a byte to its two-character hex
representation with the most significant digit on the top of the
stack.
.memory ROM rom
.varaible nibble_to_hex "0123456789ABCDEF"
.function convert_byte_to_hex
dup 0x0F & .fetchindexed(nibble_to_hex)
swap 0>> 0>> 0>> 0>> .fetchindexed(nibble_to_hex)
.return
Null-Terminated String
The null-terminator in a null-terminated string can be used by a "print"
function to terminate transmitting the string. For example, if
O_UART_Tx is the output port to a UART (and no status checking is
performed), the following will send each byte of the message to the
UART:
N"Hello World!\r\n"
:loop .outport(O_UART_Tx) .jumpc(loop,nop) drop
Note that this is equivalent to the following:
N"Hello World!\r\n"
:loop O_UART_Tx outport drop .jumpc(loop,nop) drop
The loop will transmit characters until the next character to transmit is
the null-terminator, which has the value 0, and for which the conditional
to the jumpc instruction will be false. The "nop" is
required so that the loop does not drop every other byte. The final
drop removes the null-terminator from the data stack.
Counted String
Sometimes strings to be transmitted over UARTS have null-characters embedded
within them. In this case a different method is required to
determine whether or not the end of the string has been reached. Forth's
concept of a counted string can be used to resolve this.
For example, FLIR's Tau 320 camera has the following as an example sequence
of bytes to send to the camera, which has several null bytes:
0x6E 0x00 0x00 0x08 0x00 0x02 0x0F 0x08 0x00 0x01 0x10 0x21
This sequence of bytes can be sent to the camera's serial port using the
following code:
C"\x6E\x00\x00\x08\x00\x02\x0F\x08\x00\x01\x10\x21"
:loop swap .outport(O_UART_Tx) 1- .jumpc(loop,nop) drop
Note that the count must be decremented before the conditional jump.
Lesser-Counted Strings
Since the count for a lesser-counted string is effectively pre-decremented,
the preceding example can be implemented slightly more efficiently
as:
c"\x6E\x00\x00\x08\x00\x02\x0F\x08\x00\x01\x10\x21"
:loop swap .outport(O_UART_Tx) .jumpc(loop,1-) drop