Implementing a Forth
37 points by jbauer
37 points by jbauer
Ha! I just finished implementing ANS Forth 2012 for the 6809. It started out as an attempt to figure out how to implement the Forth word DOES>
[1][2][3] and when I got that done (which required a decent amount of a working system) I just decided to continue on until it passed the ANS Forth test suite. I would say about half the words are in assembly, the rest in Forth.
[1] I’ve been interested in Forth since college, when I wrote a Forth-like language that I successfully used for both a school project, and a few programs at work. The one word I couldn’t figure out was DOES>
, which when I figured out the implementation, was mind blowing.
[2] The well known JonesForth doesn’t bother implementing DOES>
. I checked. Bummer, but I suspect I know why, because of the way it’s implemented, it would need RWX attributes on memory.
[3] An example of DOES>
: star 42 EMIT ;
: .row CR 8 0 DO DUP 128 AND IF star ELSE SPACE THEN 2* LOOP DROP ;
: shape CREATE 8 0 DO C, LOOP DOES> DUP 7 + DO I C@ .row -1 +LOOP CR ;
HEX 18 18 3C 5A 99 24 24 24 shape man DECIMAL
man
**
**
****
* ** *
* ** *
* *
* *
* *
OK
As a Forth implementor myself a long time ago (incl. DOES>
), an attempt at a somewhat simple explanation of the example:
star
is defined as a word (Forth lingo for procedure) that prints a *
..row
does a carriage return (cr
), then runs a loop 8 times (8 0 do ... loop
) which prints “*
” or “
” depending on if the bit 7 of the top of stack value is set, then multiplies the value by 2, to move through bits. The dup ... drop
pair keeps the data around during the loop and cleans up afterwards.shape
is defined as a word that creates a new word. When executing shape
it reads the next space-separated string from the input stream and create
s a new word with that name. Afterwards, but still at creation time, it runs an 8-step loop again (8 0 do ... loop
) which writes the low 8 bits of the top-most items on the stack into the word (c,
) as its data, then defines its behaviour after does>
.shape
, it is passed the address of that data storage inside itself (let’s call it data
), then executes the code after does>
. For shape, that’s: dup 7 + do i ... -1 +loop cr
, which runs a loop from data+7
downwards (-1 +loop
) to data
, starting each iteration of the loop with that address into the array (i
), the data at that place is read and printed (c@ .row
). To finish up, there’s another carriage return at the end.hex {8 values} shape man decimal
turns the interpreter to hexadecimal number decoding, puts 8 values on the stack, runs shape
which reads the next string (man
) and creates a new word with that name and those 8 values on the stack as data, then sets it (back?) to decimal number interpretation.man
finally executes the newly created word, printing the 8x8 shape encoded in those 8 hex values.OK
is the standard Forth prompt, it’s waiting for the next command.Wonderful website.
I don’t know anything about Forth but have to share this tangent. Early this month I road trip’d from SF to PDX with my wife and 3-month old baby. It was way too long of a car ride for baby, would never do that again. We stopped around Shasta in this very interesting mining town called Dunsmuir. They had a Little Free Library so of course I checked it out. Right away I spotted what had to be a classic programming book: Starting Forth. It’s interesting how, just by shape, print, fonts, etc. they are so easy to spot. Sure enough, it’s an original print from the mid-80s. And it even had a bunch of old business cards from “FIG” - Silicon Valley Forth Interest Group!
Forth implementations really lend themselves to readthroughs because they have a sense of narrative, where the system is built up piece by piece, each bit using the ones that came before. It’s almost like a creation myth: “In the beginning, God created NEXT…”
As a teenager I got a hard copy of FIG Forth for the Z-80 and read through the whole thing; it taught me a lot. As noted here, DOES was particularly tricky, introducing me to the distinction between “comptime” and runtime.