Characters and Strings
We’ll start with that perennial favorite of programmers, hello world, to illustrate how to print out a string of characters. The word to output a string is ." (pronounced dot quote). It can only be used inside a word definition, and is used thus:
: helloworld
cr
." Hello, world!"
;
Note the space between ." and the string, and the absence of a space before the final quote. That’s because ." is a Forth word, and all words must be separated by a space. The final quote character is not a Forth word, merely a string terminator, known as a delimiter. While ." may only be used inside a word definition, most other character words can be used at the command prompt.
A new line (carriage return/line feed pair) is output using the Forth word cr, and a single space character is output using the word space. For more than one space, use the spaces word that takes a parameter from the stack to specify the number of spaces to be printed:
A new line (carriage return/line feed pair) is output using the Forth word cr, and a single space character is output using the word space. For more than one space, use the spaces word that takes a parameter from the stack to specify the number of spaces to be printed:
20 spaces
|
ASCII (the American Standard Code for Information Interchange) is a widely-used character-encoding system, where an 8-bit value is used to represent a character. ASCII was introduced in 1963, and still in use today. Its successor, Unicode, is a superset of ASCII. Tables of ASCII codes and their corresponding characters are easy to find online.
|
|
To take an ACSII code from the stack and output the corresponding character, we use the word emit. For example, to output 20 spaces followed by an asterisk (ASCII code 42), we would type:
20 spaces 42 emit
The word char can be used to find the ASCII code for a given character, and place that code on the stack. For example, to find the ASCII code for the letter B:
char B
will result in 66 (decimal) on the stack.
The word digit can be used to convert a number to its corresponding ASCII code. For example, to convert the number 1 to its ASCII code:
The word digit can be used to convert a number to its corresponding ASCII code. For example, to convert the number 1 to its ASCII code:
1 digit
will result in 49 (decimal) on the stack.
digit can be used with the word emit to take a number from the stack, convert it to ASCII and print it out. On the face of it, this may seem the same as using the word . (dot) to output a number. However, dot will output a space after the number, while the above will not. This can be useful if you need to output a sequence of numbers without spaces in between.
digit can be used with the word emit to take a number from the stack, convert it to ASCII and print it out. On the face of it, this may seem the same as using the word . (dot) to output a number. However, dot will output a space after the number, while the above will not. This can be useful if you need to output a sequence of numbers without spaces in between.
Input
The Forth word key waits for a character to be input from the console, and leaves the ASCII code for that character on the stack. The word key? (key query) simply checks to see if a key has been pressed, placing a boolean (true or false) on the stack. You can use Forth to interactively tell you what the ASCII code for a character is, by using key to wait for a key press and . (dot) to print out the code for the key that was typed:
key .
The word accept is used to input a string of characters from the console. accept uses two parameters from the stack. The topmost parameter is the number of characters to be read from the console. accept will wait for this number of characters to be entered, or for a carriage return to be typed, whichever comes first. The other parameter used by accept is a pointer (address) to a scratchpad in memory where the string is to be placed. How do you know where you can put a string? Easy, Forth has a scratchpad ready for you. Use the word pad to place the address of the scratchpad onto the stack. Note that the scratchpad is not fixed in memory. It is merely a temporary storage place. As words are defined, and memory is used, the address supplied by pad will change.
To show you how this works, here is how you input 20 characters from the console:
To show you how this works, here is how you input 20 characters from the console:
pad 20 accept
accept places the number of characters actually entered back onto the stack.
Similarly, type uses an address (supplied by pad) and a count to output a string to the console. To read in a string of characters, and then print it out again:
Similarly, type uses an address (supplied by pad) and a count to output a string to the console. To read in a string of characters, and then print it out again:
pad dup 20 accept type
Note that the address provided by pad is duplicated (using the dup word), because both accept and type require it.
Inputting a Number from the Console
The Forth interpreter lets you interactively type numbers in, and places these on the stack. You can use the interpreter to process an input string of characters, and turn that into an integer. The word to do this is interpret. But first, you need to create an input buffer (which we will call mybuff) and allot some memory for that buffer. In this example, we create a buffer that is only 5 bytes deep (since the maximum integer, 65535, is only 5 characters long.)
\ create an input buffer
create mybuff 5 allot
We can the use accept to read in 5 characters to that buffer, leaving the actual number of chars entered on the stack. We place the address of mybuff on the stack, swap the char count, and call interpret. Putting it all together in a word:
: getNumber
mybuff 5 accept
mybuff swap interpret
;
Creating String COnstants in Flash
To declare a string in Forth you use the word s" followed by the string. This word creates the string in flash and returns the address of the string on the stack and the number of chars. To use the address later, you can create a variable to hold the address. (Known as a pointer in some languages.) Note s" must go inside a word, you can’t just use it at the console. So we do something like:
variable myString1
variable myString2
variable myString3
variable StringCount1
variable StringCount2
variable StringCount3
: makestring
s" wash"
StringCount1 ! \ length of string 1
myString1 ! \ store string 1 address to pointer
s" spin"
StringCount2 ! \ length of string 2
myString2 ! \ store string 2 address to pointer
s" dry"
StringCount3 ! \ length of string 3
myString3 ! \ store string 3 address to pointer
;
You can use this to allocate as many strings as you require. Then run it to allocate your strings:
makestring
You can test it created the strings by:
myString1 @ StringCount1 @ type
Comparing Strings
Now to compare strings, first we need to get the string we want to compare it to. In this example, let's read it in from the console, and compare that to one of the constant strings we created before. We need somewhere to store the input string, so we'll use the scratchpad. We need to say how many chars, and use the word accept to read them in. In this example, we'll say we'll read in 20 chars. accept will terminate before this if it gets a carriage return (new line). It will leave the actual character count received on the stack.
pad 20 accept
Forth will wait for the chars. Type wash at the keyboard followed by a return. You’ll get a char count of 4 on the stack. So we have a pointer to one string in myString1, and we have a pointer to the input string in pad. We use n= to compare them (along with a char count of our string). Now n= isn't just for strings. It can be used to compare any two sequences of data. (Note that pad is not a pointer, it's the actual location of the input string. So no @ is required for pad.)
pad \ address of our input string
myString1 @ StringCount1 @ \ pointer and count of other string
n= \ are they equal?
If they are the same we’ll get a true (-1) otherwise a false (0).
As an example of how to use this in your code:
As an example of how to use this in your code:
: test
pad myString1 @ StringCount1 @
n= if
." that's a match!"
then
;
pad 20 accept test
Next, we will look at conditional statements.