19 comments

[ 1.4 ms ] story [ 70.0 ms ] thread
2007 actually. Anyway, ask me anything!

The project comes in two parts. The first part is linked above. The second part is written in FORTH -- or rather, a subset of FORTH initially that builds up and adds features as it goes along: https://github.com/nornagon/jonesforth/blob/master/jonesfort... Try scrolling down the file, and notice how the comment syntax changes from \ (backslash) to (...) (parentheses), then notice that parenthesis-comments are implemented just before the style change. There's a lot more stuff like that, although that's the most noticeable thing for beginners.

I really enjoyed reading jonesforth. I'm just finishing up a forth app for BareMetal OS, and have been having a blast so far. Publishing tutorials is one thing, but taking the time to put together an honest-to-goodness literate program is a step beyond. Thank you for your time and effort!
Thank you so much for this. I'm one of the many who have written a FORTH with the help of this document/program and I really, really appreciate it.
> Now some easy FORTH primitives. These are written in assembly for speed.

To think again, shouldn't a modern C/C++ compiler be able to produce better code than this assembly without the intrinsic unportability? Let's take, e.g. SWAP

    defcode "SWAP",4,,SWAP
    pop %eax		// swap top two elements on stack
    pop %ebx
    push %eax
    push %ebx
    NEXT
(and NEXT is)

    /* NEXT macro. */
    .macro NEXT
    lodsl
    jmp *(%eax)
    .endm
This won't really be blazing fast, or will it?
The NEXT macro and terrible use of the stack is kind of integral to threaded code. I'll let you read the tutorial to find out why :-)

In general you shouldn't expect FORTH to be fast -- it uses the stack far too much and the way it does branching kills branch prediction on modern CPUs.

However it is very small and a lot of fun to write. If you are looking for a system that can run on baremetal and where you can completely understand the system from top to bottom, then that's FORTH for you.

Compared to C, FORTH has an extensible syntax and features like exceptions. Compared to FORTH, C is a lot easier to write significant programs in.

I am nodding along, but we can't say we write in assembly for speed, if we don't achieve much of it, can we? Especially if portable C turns out to not actually be slower.
This style of threaded code shines in making it compact. So it's useful for bootloaders and other very constrained environments.
Yeah I'm not going to defend FORTH as a practical language -- it's annoying to write significant programs in it. However it does fit in a smaller space than C (probably).

I'm currently writing an ML derivative language for smaller systems and I hope that'll be practical while at the same time being a better alternative to C.

Was this system intended primarily as a teaching and learning experience?
Yes -- although mainly as a learning experience for me. It was also a lot of fun to think about and write.
Are you familiar with BootForth - a 'Forth bootstrapping framework'? It was originally announced in 2008 in comp.lang.forth https://groups.google.com/forum/#!topic/comp.lang.forth/tc_O...

Maybe by chance you even have the source? It seems to have disappeared from the net, together with Gitorious, and the original author is unavailable.

No - I've not heard of that one.
Back in the 1980's I had a TRS-80 color computer which was running a Unix-clone operating system called OS-9, this was multi-tasking and multi-user so I could log into my Coco with a DEC Correspondent printing terminal.

I wrote a FORTH implementation for the 6809 in about 3k lines of assembly code which included the language plus the 'standard library'. Instead of the 'standard' Forth I/O, there was an interface to Unix-style file-handle based I/O. It used subroutine threading so that FORTH compiled directly to 6809 code and the part that did dynamic dispatch used self-modifying code to shave off a few cycles.

FORTH is an interesting part of the story about why LISP didn't take off on 1980's microcomputers, partly because if you wanted a LISP on an 8-bit micro, you could get much of the way there with FORTH in a footprint even smaller than BASIC.

How hard would it be to port this to x86_64? Offhand I'm guessing the alignment, register names (eXX -> rXX), changing any relative offset from 4 to 8, and syscall convention. Any other hidden landmines?
Read it once more, and it was a good way to remind me of how fun programming was before we had megabyte libraries and dozens of layers of abstraction.

I also noticed something that made me smile:

"There is no generally agreed syntax for this, so I've gone for the syntax mandated by the ISO standard"

You won't read that in the source code of a C, pascal, or Fortran compiler, and there basically is only one forth standard, but historically, many implementations know better than to follow it. That is both a good and a bad thing.

On the plus side, it is extremely flexible, but the price one pays for that is that there is barely any code reuse because every system is different.

For systems on which Forth shines, that isn't a problem. There, you do not include that 400 byte floating point library "as is", but take the source, remove the 2% of it that you do not need, and tweak a few calls to make them smaller at the price of performance because you don't have 400 bytes to waste on a bloated floating point package. You don't program in Forth, you write a forth.