Over the years, I keep coming back to the Forth programming language. I admire its lean design and very efficient use of resources, but oh, is it ever quirky. My most recent return was motivated by James Bowman’s J1 Forth CPU, a small but blazingly fast FPGA-based processor.
My ambivalence with Forth started back in the 1980’s, when an engineer named Tom Harsch mentored a very young me in digital electronics and computer architecture. Tom is an all-around engineer, versed in both hardware and software. He had a fondness for Forth, and he introduced it to me. Or perhaps I should say
ME FORTH TOM INTRODUCED
You see, the very first quirk one runs into when encountering Forth is its use of postfix notation to represent operations. While mainstream languages like BASIC and C would have syntax resembling this,
print 2 + 3
Or this,
printf(“%d\n”, 2 + 3);
Forth, in common with German, likes its verbs last. Here’s the Forth version:
2 3 + .
Don’t overlook that period, “.”, at the end. In Forth, that does not end a sentence; it is the command for printing a number.
Postfix notation is intellectually appealing, for several reasons. In postfix, every operation can be expressed with the same basic syntax, so there is no longer a need to distinguish between infix operators (+, -, *, etc.), unary prefix operators (like negation, -), and function calls. They all fit the same basic syntactic framework. Another advantage is that it maps very simply onto a stack-based processor model, which in turn can be implemented reasonably efficiently on many traditional CPUs or which really flies on dedicated hardware.
Forth uses postfix notation to permit the implementation of a simple compiler, which is usually built right into the run-time environment. The simplicity of the compiler results in further bizarre constructs, like the IF…ELSE…THEN statement. Not only are “ELSE” and “THEN” ordered backwards from pretty much every other language in the world, thanks to postfix notation, the “THEN” keyword comes after the code for the ELSE:
( condition ) IF ( then-actions ) ELSE ( else-actions ) THEN
On the bright side, this did give rise to a classic bumper sticker from the Forth Interest Group:
FORTH LOVE IF HONK THEN
Defining a function is straightforward, if you don’t mind punctuation:
: 2times 2 * ;
The colon (:) command defines a new “word” for the language. The next text, “2times”, is the name of the new word. That is followed by the instructions for the word and a semicolon (;) that ends the definition.
So what does this new word do? It multiplies whatever number came before it by 2. “5 2times .” is equivalent to “5 2 * .” and prints the number 10.
This syntax is admirably compact and naturally lends itself to a functional style. On the other hand, what is the name of the word doing after the colon? In a postfix language, I would expect to quote the name and the function body, then use the defining word. Something like this:
‘2times (2 *) :
Flip that around and add a “lambda” and it starts to look like LISP, but that’s a subject for another time. In Forth, this kind of quirkiness, where everything is postfix except for the parts that aren’t, is standard. It keeps Forth’s compiler simple, but at a cost in elegance.
Syntactic quirkiness aside, Forth has a few things going for it. First, it makes extremely efficient use of machine resources. A reasonable Forth environment can fit in 4K of RAM and include a compiler, an interpreter, and room for a small application. A full-featured environment is larger, but still takes less resources than equivalent functionality in other languages. Forth is generally fairly speedy, too.
Forth is extremely versatile. The compiler is implemented in an extensible way. You can define Forth words that alter how the compiler works, giving another way to work at higher levels of abstraction.
The philosophy behind Forth encourages programs to be organized in a hierarchy of small, simple functions. Each layer of functions builds a higher level of abstraction than the one that lies below it. I like this kind of well-factored programming, and it would be nice to work in a language that encourages it.
That brings me to the J1 Forth CPU. This compact Verilog core is a work of brilliance, particularly in the way it uses the FPGA’s dual-port RAM in a carefully designed data path to achieve a high instruction rate. The instruction set architecture is pretty much pure Forth, and the implementation was written to be fast. James Bowman’s paper on the J1 (pdf) is well worth a read, and so is the Verilog source code.
Ever since I read the J1 paper, I’ve been itching to find a use for it. (Yes, I know, that’s a solution in search of a problem…) My oft-delayed R2/T2 transceiver project offered a chance. As I thought about what to put on the front panel, my mind strayed to thoughts of touch-panel LCDs. Wouldn’t it be nice to be able to defer most of the user interface decisions to software? It’s much easier to move a button on a screen than to un-drill a hole. eBay has a number of nice touch panels that would fit my chosen case perfectly.
Besides, I’ve been getting in a bit of a rut lately. Though there was a time when I learned every language I could find, lately I’ve been using C almost all the time. How better to shake things up than by implementing a touch-screen user interface in Forth? My favorite way to learn a new language is to dive into a major project. In fact, I learned C by writing a text editor. Next I learned C++ by writing two text editors. Then I learned Tcl by writing a text editor, and Prolog by writing tax software. (Go figure.)
Eventually I came to my senses. First off, I’m so busy these days that I’m finding it hard to spend any time on the R2/T2, let alone write graphics software for it. A more serious problem, though, is that the Actel FPGA I have handy has only 6K of RAM and limited capability for ROM or flash. To do the graphical user interface, I would want fonts in two sizes, and the J1 on this FPGA would not be able to store even one. I was brainstorming ways to extend the J1’s address space into off-FPGA storage when I had my Arduino epiphany. It does not make sense to spend time engineering complex font storage when a cheap, off-the-shelf processor has 32K of flash and the gcc C compiler at the ready.
Even with the Arduino standing by, I can’t get avoid being busy. No, the R2/T2 will have to make do with switches and knobs. Maybe in the future I can replace them with a touchscreen.
That settled, only one problem remains: I no longer have a problem for the J1 and Forth to solve.
Oh, well…
Updated 1/18/13 to correct the IF…ELSE…THEN syntax.