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.
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 ;
k= has the following definition (but it's not relevant for the example);
: k= inkey = ;
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 the
xvariable 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 ! ;
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.
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 ;
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.