Programming in Forth with Forth style
Description of the page content
Some examples of Forth code written without the Forth style, and how to rewrite them.
Sometimes I've found Forth code that is written without the Forth style. This page shows two examples, and how I rewrote them. This page is a brief version of the original article in Spanish, with step by step changes in the code.
Example 1
In Sideras (page in Spanish), a little game written in Ace Forth by an unknown author, I found the following word:
: izq
x @ 0 > ascii 5 k= and
if
x c@ 1- x !
then
;
The word k=
has the following definition (but it's not relevant for the example);
: k= inkey = ;
The word izq
(abbreviation of "left" in Spanish) tests the 5 key and, if the player's x coord is more than zero, it is decreased.
It works... But it's not the Forth's style. Here you are my alternative:
: izq x dup @ ascii 5 k= - 0 max swap ! ;
Result:
| |= original code |= new code | |= words | 15 | 11 | |= control structures | 1 | 0 | |= calculations | 2 | 1 | |= times thex
variable is mentioned | 3 | 1 |
In Ace Forth, the result of a boolean operation is 0 or 1. In ANS Forth the result is 0 or -1 (more useful and logical), so the code would be:
: izq x dup @ [char] 5 k= + 0 max swap ! ;
Example 2
Let's see a larger example. The listing of Chase, a little game for the Jupiter Ace, was published by Andrew Curtis in Popular Computing Weekly in 1983.
Original code
The original code is almost ilegible:
10 VARIABLE X
15 VARIABLE Y
1 VARIABLE A
1 VARIABLE B
: CHASE CLS 10 X ! 15 Y ! 1 A ! 1 B ! BEGIN X @ Y @ AT ." " A @ B @ AT ." " INKEY 53 = IF Y @ 2 - Y ! THEN INKEY 54 = IF X @ 2 - X ! THEN INKEY 55 = IF X @ 2 + X ! THEN INKEY 56 = IF Y @ 2 + Y ! THEN X @ 20 > IF 20 X ! THEN Y @ 30 > IF 30 Y ! THEN X @ 1
< IF 1 X ! THEN Y @ 1 < IF 1 Y ! THEN X @ A @ = IF Y @ B @ = IF ." GOT YOU!" 250 1000 BEEP QUIT THEN THEN X @ A @ > IF A @ 1+ A ! THEN X @ A @ < IF A @ 1– A ! THEN Y @ B @ > IF B @ 1+ B ! THEN Y @ B @ < IF B @ 1– B ! THEN X @ Y @ AT ." A" A @ B @ AT
." E" 250 70 BEEP 0 1 = UNTIL ;
In lowercase and with proper indentation, the code looks much better. It's clear the code was written with the style of BASIC: many conditionals, and many redundant calculations.
10 variable x
15 variable y
1 variable a
1 variable b
: chase
cls
10 x ! 15 y !
1 a ! 1 b !
begin
x @ y @ at ." "
a @ b @ at ." "
inkey 53 = if y @ 2 - y ! then
inkey 54 = if x @ 2 - x ! then
inkey 55 = if x @ 2 + x ! then
inkey 56 = if y @ 2 + y ! then
x @ 20 > if 20 x ! then
y @ 30 > if 30 y ! then
x @ 1 < if 1 x ! then
y @ 1 < if 1 y ! then
x @ a @ = if
y @ b @ = if
." got you!" 250 1000 beep quit
then
then
x @ a @ > if a @ 1+ a ! then
x @ a @ < if a @ 1– a ! then
y @ b @ > if b @ 1+ b ! then
y @ b @ < if b @ 1– b ! then
x @ y @ at ." A"
a @ b @ at ." E"
250 70 beep
0 1 =
until
;
Modified code
This is my version, with no conditional structure, simplified calculations and simpler main loop:
10 variable x
15 variable y
1 variable a
1 variable b
: chase
cls
10 x ! 15 y !
1 a ! 1 b !
begin
x @ y @ at space
a @ b @ at space
y @ inkey 53 = 2 * - inkey 56 = 2 * + 1 max 30 min y !
x @ inkey 54 = 2 * - inkey 55 = 2 * + 1 max 20 min x !
x @ a @ = y @ b @ = and 0=
while
a @ x @ over > + x @ a @ < negate + a !
b @ y @ over > + y @ b @ < negate + b !
x @ y @ at ." A"
a @ b @ at ." E"
250 70 beep
repeat
." got you!" 250 1000 beep
;
It's almost Forth style, but not completely: Factoring is needed. Instead of one large word, many little specialized and independent words are better: the code gets easier to read and mantain.
The result of factoring the code of Chase became a new program: Heat Seeker.