Forth DSL example

Forth is a language, like Lisp, that has a certain fascination for me. I’ve tried Forth a few times, but have always gone back to other languages. Recently I tried creating a Forth myself as a learning exercise: ultimc [1]. It compiles on Linux, Windows (theoretically), and under the Ultibo [2] unikernel for a bare metal Raspberry Pi Forth.

Creating my own Forth has taught me a lot about the language, and really made me understand the way it works. In this post, I am going to peer a little under the hood to show that Forth, like Lisp, has a secret sauce that you just don’t get with most other languages. Maybe it will excite you a little as to the unique possibilities of Forth.

Recently I came across some Forth code [3] that was as follows:

0 constant: GPIO_INTTYPE_NONE
1 constant: GPIO_INTTYPE_EDGE_POS
2 constant: GPIO_INTTYPE_EDGE_NEG
3 constant: GPIO_INTTYPE_EDGE_ANY
4 constant: GPIO_INTTYPE_LEVEL_LOW
5 constant: GPIO_INTTYPE_LEVEL_HIGH

Notice how there’s a lot boilerplate code there: “0 constant:”, “1 constant:”, etc. Wouldn’t it be nice to write something like:

enum: GPIO_INTTYPE_NONE GPIO_INTTYPE_EDGE_POS GPIO_INTTYPE_EDGE_NEG ...

and have Forth “do the right thing”. Well, let’s see …

Here’s the code, written in gforth:
variable enum \ the current enumerated value, starting at 0
: enum++ enum @ dup 1+ enum ! ; \ increment enum, leaving the original enum value on the stack
: >enum nextname enum++ constant ; \ Given a name, set it to the value of enum as a constant
: enum1 parse-word dup if >enum 0 else 2drop 1 then ; \ scan the input buffer, and call >enum if legit
: enum: begin enum1 until ; \ keep going until the input buffer is exhausted

Just 5 lines of code, although admittedly it did take me a lot of time to figure out. The code needs a little elaboration.

PARSE-WORD and NEXTNAME act a little bit like CREATE, except that PARSE-WORD gets the next word from the input buffer, and NEXTNAME creates a word from the input buffer.

Now, if we’re at the end of the buffer PARSE-WORD returns a zero length string. This is what ENUM1 checks for. It only calls >ENUM if the string has at least 1 character. What it returns on the stack is the value 0 to signify success, and 1 to signify failure.

ENUM: then just loops around until the value 0 appears on the stack, implying that the input buffer is exhausted.

Let’s test it, using more condensed names:

enum: foo bar baz

And check our handiwork:

foo . bar . baz . \ outputs: 0 1 2

Can your language do that?

References
[1] https://github.com/blippy/ultimc
[2] https://ultibo.org/
[3] https://github.com/zeroflag/punyforth/blob/master/arch/esp8266/forth/gpio.forth

Advertisements

About mcturra2000

Computer programmer living in Scotland.
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s