Back in Forth
For the past few weeks, I've been spending about a third of my time programming in Forth. Originally, I was playing around with 4€4th on the MSP430. The MSP430 is a lovely little chip with just enough RAM to be interesting. At 1 to 16MHz and a hardware UART, it has that first computer feeling. The 4€4th package takes up about half the available space, leaving just enough for something interesting. My goal for this board is to act as an aggregator for sensor data, as the chip w/ a basic board runs about $4. Forth makes that tiny space feel spacious.
On a whim, about 3 weeks ago I bought some rather retro reading:
And found it wonderfully remedial. There were a few features of Forth I had totally forgotten over the years. I started programming when fig-forth83 came out. When the 1994 ANSI standard, I got a part-time gig as a C programmer and only whipped out Forth for fun over the next 20 years. On two occasions I got to professionally use my Forth skills, once building a custom Postscript application, and the other building an interpreter for a game engine. But for the better part of the past 20 years, Forth has been a hobby.
The past two weeks, however, I've begun seriously reevaluating that relationship. Part of the reason for this is I am now writing code for 4 architectures simultaneously. Most of the languages I've been using don't even fit on two of the boards I'm building applications with, and while I have C cross-compilers for each, I've found JTAG debugging C code to be lacking in elegance.
So thinking back in my past, why not dredge up a tool from the bottom of my bag of tricks? So I started implementing a couple applications in Forth. The first (or second) is a AMQP wire protocol encoding app. The goal here is to encode AMQP frames and send them over wifi to a RabbitMQ server elsewhere in the cloud. I may also use them to shuttle structured data between apps on a 2-wire bus between components. It looks like an operational stack will take 4k of RAM to run, but with some streaming techniques, I may be able to stay below that. Right now I'm working on the socket code for the test rig, but hope to have basic.publish messages working soon.
The second application (or first to finish) is a HTTP/1.1 webserver written in Forth. This code took a couple hours to write, but a couple days to figure out how to make gforth explain why bind(2) was failing. That required an excursion into libffi and learning the hackish way gforth binds to C with auto-generated stub files in ~/.gforth/... and chasing my tail until rm -rf ~/.gforth/ solved the problem. The end result of that process of hating gforth to accepting it as a useful tool.
The HTTP server uses a few fun tricks from an article I read once, but can't seem to find again. Rather than implementing a parser, and doing a lot of work managing data structures like Apache, or building giant ass request / response objects like Node, I just evaluate the HTTP request as Forth code. This works incredibly well, and even use evaluation to do the dynamic dispatch of the path routing. There are some basic security measures left to implement, like locking down the dictionary to a HTTP only word list, but that problem has been solved in Forth for at least 30 years. I will probably make the path parsing and dispatch code more complicated to do more things, and process longer paths (currently limited to 255 chars) but for a simple embedded webserver that runs in about 4k, it is pretty impressive. In about 200 lines of Forth, I should be able to implement a high performance, modern web server, and that makes me seriously question why shouldn't I use Forth as my daily language of choice.