Forth in 100 Steps (Sample)
Forth in 100 Steps (Sample)
00
To know a bit more about the Forth language, let’s Here we go:
launch gforth in a terminal.
gforth ←-
Gforth 0.7.2, Copyright (C) 1995-2008
Free Software Foundation, Inc.
Gforth comes with ABSOLUTELY NO WARRANTY;
for details type ‘license’
Type ‘bye’ to exit
01
Forth uses a Stack as a way to pass parameters to, 42 ←- ok
17 ←- ok
and get results from operations. Entering numbers will
4807 ←- ok
put these numbers on the Stack. Enter two numbers.
02
You can print the number that is currently at the top . ←- 4807 ok
. ←- 17 ok
of the Stack, using the dot symbol: . . ←- 42 ok
03
Printing the number removes it from the Stack. Put
two numbers on the Stack again. You can enter several 47 150 ←- ok
numbers on the same line.
04
You can add the two numbers at the top of the Stack Let’s try:
by entering the + sign.
+ ←- ok
. ←- 197 ok
1
05
Just like numbers, the + and . symbols should be 42 17 +. ←-
:8: Undefined word
separated by space. Try not separating them and see 42 17 >>>+.<<<
what you get. (We don’t need to know about the trace Backtrace:
information for now). $103D82A08 throw
$103D98C90 no.extensions
$103D82CC8 interpreter-notfound1
06
Other arithmetic operations are available as well. 47 150 - . ←- -103 ok
47 150 * . ←- 7050 ok
They all use the Stack as a container for integer values. 150 47 / . ←- 3 ok
Try them. 4807 47 / . ←- 102 ok
07
Enter two numbers on the Stack, add them, then OK.
multiply the result by another number.
4807 3 + 42 * . ←- 202020 ok
08
To get the remainder of a division, use MOD. 4807 42 MOD . ←- 19 ok
09
You can also obtain both quotient and remainder, 4807 7 /MOD ←- ok
using the word /MOD. The quotient will be at the top of . ←- 686 ok
the Stack, and the remainder will be just below the top. . ←- 5 ok
0A
Enter a number, then print its opposite, using 17 NEGATE . ←- -17 ok
NEGATE.
0B
Print 32% of 4807 (approximately). 4807 32 * 100 / . ←- 1538 ok
0C
Give a more precise result (still using integer val-
ues). You can print the integer part and the fractional 480700 32 * 100 / 100 /MOD . . ←- 1538 24
part separately.
0D
Enter two numbers, then print the greatest number, 42 17 MAX . ←- 42 ok
using MAX.
0E
Enter two numbers, then print the smallest number, 42 17 MIN . ←- 17 ok
using MIN.
0F
Enter four numbers on the Stack, and print the 42 17 255 -13 MAX MAX MAX . ←- 255 ok
greatest number.
2
1 Arrange
10
Numbers are usually removed from the Stack by the 42 DUP ←- ok
. . ←- 42 42 ok
words that use them. If you want to keep a number on
the Stack and use it as a parameter for a word, you can . .
42 DUP
duplicate it, with the word DUP.
42 42 42
Draw the successive states of the Stack to better under-
42
stand the way it works.
11
Find a sequence of words that computes the square 42 DUP * . ←- 1764 ok
-7 DUP * . ←- 49 ok
of a number without typing the number twice. Try your
sequence on several values. .
42 DUP *
42 42 1764
42
12
Ask gforth to compute the value of 24 and 28 . 2 DUP DUP DUP * * * . ←- 16 ok
3
13
When you want a copy of the number just below the 42 17 OVER . . . ←- 42 17 42 ok
top instead of a copy of the top, use OVER. Try it.
42 17 OVER . . .
42 17 42 17 42
42 17 42
42
14
Find a sequence of words that given two numbers a 42 17 OVER + . . ←- 59 42 ok
and b, leaves the Stack with the numbers a, a + b.
42 17 OVER + . .
(Remember that repeating . will print the stack content
in reverse order). 42 17 42 59 42
42 17 42
42
100 99 OVER + . .
100 99 100 199 100
100 99 100
100
15
Sometimes you need to exchange the top of the 42 17 SWAP . . ←- 42 17 ok
Stack with the number just below. That’s when you
42 17 SWAP . .
use the word SWAP.
42 17 42 17
42 17
16
Find a sequence of words that given two numbers a 42 17 SWAP 100 * SWAP / . ←- 247 ok
and b, will compute (approximately) 100a
b .
42 17 SWAP 100 * SWAP / .
42 17 42 100 4200 17 247
42 17 42 17 4200
17
4
17
You can also move the value that is in the third po- 1 2 3 ROT . . . ←- 1 3 2 ok
sition to the top of the Stack using ROT.
1 2 3 rot . . .
1 2 3 1 3 2
1 2 3 2
1 2
42 17 4807 ROT . . .
42 17 4807 42 4807 17
42 17 4807 17
42 17
18
Using OVER twice duplicates the two numbers at the 42 17 OVER OVER ←- ok
. . . . ←- 17 42 17 42 ok
top of the Stack1 .
42 17 OVER OVER . . . .
42 17 42 17 42 17 42
42 17 42 17 42
42 17 42
42
19
Using ROT twice rotates the number at the top of the Ok
Stack under the number just below the top2 .
1 2 3 ROT ROT . . . ←- 2 1 3 ok
1 2 3 ROT ROT . . .
1 2 3 1 2 1 3
1 2 3 1 3
1 2 3
1A
Enter three numbers, then print them in the order Easy:
they were entered. 1 2 3 SWAP ROT . . . ←- 1 2 3 ok
1 2 3 SWAP ROT . . .
1 2 3 2 1 2 3
1 2 3 2 3
1 1 3
5
1B
Enter two numbers, then print them in ascending 42 17 OVER OVER MAX ROT ROT MIN ←- ok
. . ←- 17 42 ok
order. Test your sequence by entering the numbers in a
different order.
42 17 OVER OVER MAX ROT ROT MIN
42 17 42 17 42 42 17 17
42 17 42 17 42 42 42
42 17 42 17 42
42
1C
In your last test, replace the sequences OVER OVER 42 17 2DUP MAX -ROT MIN ←- ok
. . ←- 17 42 ok
and ROT ROT with faster words 2DUP and -ROT.
42 17 2DUP MAX -ROT MIN
42 17 17 42 17 17
42 42 17 42 42
17 42 42
42
1D
Enter three numbers, then print them in ascending 42 17 4807 ←- ok
2DUP MAX -ROT MIN ( 42,4807,17 ) ←- ok
order, using the sequence for sorting two numbers. ROT ( 4807,17,42 ) ←- ok
You can use ( and ) to comment on what happens on 2DUP MAX -ROT MIN ( 4807,42,17 ) ←- ok
the Stack3 . -ROT ( 17,4807,42 ) ←- ok
2DUP MAX -ROT MIN ( 17,4807,42 ) ←- ok
ROT ( 4807,42,17 ) ←- ok
. . . ←- 17 42 4807 ok
42 17 4807 2DUP MAX -ROT MIN ROT 2DUP MAX -ROT MIN -ROT 2DUP MAX -ROT MIN ROT
42 17 4807 4807 4807 4807 17 42 42 42 42 17 42 42 4807 42 42 17
42 17 17 4807 17 4807 17 17 42 17 42 4807 4807 42 4807 4807 42
42 4807 17 4807 42 4807 42 17 42 4807 17 42 4807 4807 17 4807
17 42 42 17 4807 4807 4807 17 17
42 4807 17
3 Be careful: ( is a Forth word, i.e. it must be separated from the first word of comment by a space.
6
1E
When you don’t need a number on the Stack any 42 17 DROP . ←- 42 ok
more, you can get rid of it with DROP.
1F
The word 2DROP is a faster way to execute
DROP DROP in order to eliminate 2 values from the 42 17 23 2DROP . ←- 42 ok
Stack.
→ ROT ( a,b,c -- b,c,a ) : rotates the value in the third position to the top of the Stack.
→ -ROT ( a,b,c -- c,b,a ) : rotates the top of the Stack to the third position.
→ 2DUP ( a,b -- a,b,a,b ) : duplicates the two values at the top of the Stack.
→ 2DROP ( a,b -- ) : removes two numbers from the top of the Stack.
7
2 Display
20
We can display characters instead of numbers. The 65 EMIT ←- A ok
word EMIT consumes the value at the top of the Stack
and prints the corresponding character on the terminal.
21
We will use the following ASCII codes to represent 35 EMIT ←- # ok
36 EMIT ←- $ ok
the elements of the puzzle. Try them if you want.
42 EMIT ←- * ok
wall : 35 crate : 36 43 EMIT ←- + ok
filled goal : 42 worker on goal : 43 46 EMIT ←- . ok
64 EMIT ←- @ ok
goal : 46 worker : 64
22
The code for space (or Blank) is frequently used, so BL . ←- 32 ok
there is a word for it: BL, and even an equivalent of the SPACE SPACE SPACE ←- ok
sequence BL EMIT, called SPACE.
23
The word CR sends a Carriage Return on the termi- CR CR CR ←-
nal, forcing the display to start on a new line.
ok
CHAR N ←- ok
24
One way to put a character on the Stack is to enter CHAR A ←- ok
its ASCII code, if you know that code. Another way is CHAR B ←- ok
to use the word CHAR. CHAR reads the following word CHAR O ←- ok
CHAR K ←- ok
on the entry as the litteral char you want to have on the CHAR O ←- ok
Stack. Try it!. CHAR S ←- ok
Display the word SOKOBAN on the terminal. CR EMIT EMIT EMIT EMIT EMIT EMIT EMIT ←- ok
SOKOBAN ok
This takes some work!
8
25
Here is a faster way to display characters: use the ." SOKOBAN" ←- SOKOBAN ok
." Foo Bar" ←- Foo Bar ok
word .", and all the following non space characters in
the flow of entry will be printed until a " is met.
Don’t forget that ." is a word in itself and must be sep-
arated from the rest of the entry.
26
The terminal can do other actions than just display CR 9 EMIT 9 EMIT 35 EMIT ←-
characters. For example, the character with code 7 will # ok
ring a bell, and 9 will send a tabulation.
27
Some complex actions on the terminal are initiated
by the character with code 27 (ESC), followed by a [
27 EMIT ." [2J" ←-
and a command.
For example, to clear the entire screen, display the es-
cape character followed by the string [2J.
ok
28
Another terminal escape command allows you to 27 EMIT ." [5;3H" 42 EMIT ←-
select the column and row of the terminal where you
want to display the next characters. Try the escape
* ok
command 5;3H for example.
29
The gforth vocabulary includes special words that PAGE 2 2 AT-XY 46 EMIT 5 3 AT-XY 42 EMIT ←-
use terminal escape commands: PAGE will clean the
screen; AT-XY will take two numbers on the Stack and
.
use them as the x and y coordinates of the next thing to * ok
be displayed.
2A
The gforth word ESC[ is doing the same as the se- ESC[ ." 4m" ." Foo" ESC[ ." 0m" ." Bar" ←-
FooBar ok
quence: 27 EMIT 91 EMIT would: it sends these con-
trol characters to the terminal.
For example try to print words using underlined (4m)
mode, and then get back to normal mode (0m).
2B
The terminal can also print characters in color. Just
ESC[ ." 31mFoo" ←- Foo ok
print the escape sequence, then the color number, for CR ESC[ ." 32mFoo" ←- Foo ok
instance 31, for red, followed by m. CR ESC[ ." 34mBar" ←- Bar ok
Try to print lines using different colors.
2C
To reset all the terminal display attributes, use the CR ESC[ ." 0mQux" ←-
Qux ok
word ESC[ then print the string 0m.
9
2E
Try with the word .R (dot-R). This word takes two
numbers n, w and prints n aligned on the right on w 4807 10 .R ←- 4807 ok
42 2 .R 17 2 .R ←- 4217 ok
columns. If w columns are not enough to print the num-
32 0 .R CHAR m EMIT ←- 32m ok
ber, .R will display the whole number anyway. The
important thing is that it will do it without adding a
trailing space like . does. I see.
2F
Try again this time using 0 .R in your sequence. 34 ESC[ 0 .R 109 EMIT ." Foo" ←- Foo ok
35 ESC[ 0 .R CHAR m EMIT ." Foo" ←- Foo ok
32 ESC[ 0 .R CHAR m EMIT ." Foo" ←- Foo ok
0 ESC[ 0 .R CHAR m EMIT ." Foo" ←- Foo ok
→ .R ( n,w -- ) : prints the number n aligned on the right on w columns, with no trailing space.
10
3 Define
30
Forth lets you define your ow words. Cool!
Here’s how to create a new word:
: STAR 42 EMIT ; ←- ok
→ start with : (colon), a space, and the name you STAR ←- * ok
want to give to your new word, STAR STAR STAR ←- *** ok
31
Create a definition for a word called SQUARE that Ok!
takes a number n on the top of the Stack and replaces it
: SQUARE DUP * ; ←- ok
with n2 . 42 SQUARE . ←- 1764 ok
Then create a word called CUBE that takes a number n -7 SQUARE . ←- 49 ok
on the top of the Stack and replaces it with n3 . Use the
: CUBE DUP SQUARE * ; ←- ok
previous word you just created.
42 CUBE . ←- 74088 ok
Try your definition with several examples. -3 CUBE . ←- -27 ok
32
Create a word named SORT2 that given 2 values on : SORT2 2DUP MAX -ROT MIN ; ←- ok
42 17 SORT2 . . ←- 17 42 ok
the Stack, sorts them so that the greater value is below
17 42 SORT2 . . ←- 17 42 ok
the top, and the smaller value is at the top.
33
Create a word named SORT3 that given 3 values on
: SORT3 SORT2 ROT SORT2 -ROT SORT2 ROT ; ←-
the Stack sorts them so that the greatest value is below 42 17 4807 SORT3 . . . ←- 17 42 4807 ok
the two others on the Stack, and the smallest is at the 243 39 -55 SORT3 . . . ←- -55 39 243 ok
top.
11
34
Create a word named MODE that given a number, That is the sequence I defined some time ago:
sends an escape command to the terminal with that
: MODE ESC[ 0 .R CHAR m EMIT ; ←- ok
number. :23: Undefined word
Try your word with different modes. : MODE ESC[ 0 .R CHAR >>>m<<< EMIT ;
35
Oh. I forgot to mention that CHAR cannot be used OK.
inside a definition4 . Use [CHAR] instead.
: MODE ESC[ 0 .R [CHAR] m EMIT ; ←- ok
31 MODE ←- ok
34 MODE ←- ok
35 MODE ←- ok
0 MODE ←- ok
CR 4 MODE ." Foo" 0 MODE ." Bar" ←-
FooBar ok
That is better!
36
Create a word BLUE that switches the display color Easy:
to red, and a word NORMAL that restores all display at-
: BLUE 34 MODE ; ←- ok
tributes to normal. : NORMAL 0 MODE ; ←- ok
37
You can keep your programs in script files. When That’s cool, now I can write a program!
gforth is launched with the name of a script file as an : MODE ESC[ 0 .R [CHAR] m EMIT ;
argument, the words in the file are automatically exe-
cuted as gforth starts. : BLUE 34 MODE ;
Edit a Forth script file called Sokoban.fs. Enter your
definitions, and execute a simple sequence of actions : NORMAL 0 MODE ;
using these definitions. Note that ending the file script
with the word BYE will tell gforth to quit right after BLUE CHAR @ EMIT NORMAL CR BYE
executing the last word, giving us a stand-alone Forth Sokoban.fs
program. Try it!
gforth Sokoban.fs ←-
@
It works!
38
Comments can be entered after the word \ or be- Ok.
tween ( and ). Stack comments, like in this instance \ Sokoban.fs A Game of Sokoban in Forth!!
: NIP ( a,b -- b )
SWAP DROP ; : MODE ESC[ 0 .R [CHAR] m EMIT ;
are very usual.
: BLUE 34 MODE ;
4 Here’s the reason: CHAR reads the entry flow, looking for the next word, and then puts the char value on the Stack, while [CHAR] reads the
entry flow, looking for the next word, and then compiles the char value in the definition that is currently going on. CHAR used inside a definition,
is inactive. Thus the following item in the entry, m causes an Undefined word error.
12
39
You should keep your definitions small and elegant. Ok.
For that purpose, you can always create some helper \ Sokoban.fs A Game of Sokoban in Forth!!
words. For example:
→ replace [CHAR] m EMIT with a word called .M : .M [CHAR] m EMIT ;
3A : RED 31 MODE ;
Create new words to display the elements of the
: GREEN 32 MODE ;
game. Here they are:
: YELLOW 33 MODE ;
: BLUE 34 MODE ;
element display mode : NORMAL 0 MODE ;
empty space 0 : DISPLAY-EMPTY NORMAL BL EMIT ;
: DISPLAY-WORKER BLUE [CHAR] @ EMIT ;
worker @ 34
: DISPLAY-ONGOAL BLUE [CHAR] + EMIT ;
worker on goal + 34
: DISPLAY-CRATE GREEN [CHAR] $ EMIT ;
walls # 31 : DISPLAY-WALL RED [CHAR] # EMIT ;
crates $ 32 : DISPLAY-GOAL GREEN [CHAR] . EMIT ;
goal . 32 : DISPLAY-FILLED YELLOW [CHAR] * EMIT ;
filled goal * 33 \ testing
DISPLAY-WORKER DISPLAY-CRATE
DISPLAY-WALL DISPLAY-EMPTY
DISPLAY-GOAL DISPLAY-FILLED
DISPLAY-ONGOAL BYE
gforth Sokoban.fs ←-
@$# .*+
It works!
3B
Your program can be made simpler. Do you see all Ok.
these repeated patterns in the definitions? Instead, we : DISPLAY MODE EMIT ; \ chr,col --
can define one general word: DISPLAY that given an
ascii code and a color number, will display that charac-
ter in that color.
gforth Sokoban.fs ←-
@$# .*+
13
3D
We can simplify the code a bit more. All these Ok.
DISPLAY-xxx have the same structure. We can define \ Sokoban.fs A Game of Sokoban in Forth!!
specialized words, and use them by combining them
with DISPLAY. : .M [CHAR] m EMIT ;
Create words WORKER, ONGOAL, WALL, etc. that will
push the right codes on the Stack. : .N 0 .R ; \ n -- print n w/o trailing space
: WORKER [CHAR] @ 34 ;
: ONGOAL [CHAR] + 34 ;
: WALL [CHAR] # 31 ;
: CRATE [CHAR] $ 33 ;
: GOAL [CHAR] . 32 ;
: FILLED [CHAR] * 35 ;
: EMPTY BL 0 ;
\ testing
WORKER DISPLAY CRATE DISPLAY
WALL DISPLAY EMPTY DISPLAY
GOAL DISPLAY FILLED DISPLAY
ONGOAL DISPLAY BYE
3E
Words like RED, BLUE, etc. that just push a number 42 CONSTANT ASTERISK ←-
ASTERISK EMIT ←- * ok
on the Stack can be declared as constants rather than
colon definitions. I see.
The word CONSTANT takes a number on the Stack, and
creates a new definition with the name that follows. Try
it with gforth .
\ testing
WORKER DISPLAY CRATE DISPLAY
WALL DISPLAY EMPTY DISPLAY
GOAL DISPLAY FILLED DISPLAY
ONGOAL DISPLAY BYE
14
→ Forth lets you create new words that can be used just like existing words.
→ : ( {XXX ... ;} ) : creates a new definition named XXX for the following sequence.
→ At run time, a word created with : will execute the words contained in its definition.
→ ; : ends a colon definition.
→ You can redefine words simply by writing their new definition with : and ;.
→ [CHAR] {X} ) : inside a colon definition, reads the next character on the entry and compiles its
ASCII code in the definition.
→ CONSTANT ( {XXX} n -- ) : defines a constant named XXX for the value n.
→ At run time, a word created with CONSTANT will put its value on the Stack.
→ Invoking gforth with a script name executes all the words in the script file.
15