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!
> 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
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.
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.
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?
Kind of a bunch of work, but at the same time it'd be an interesting learning exercise. There have been ports to quite different architectures, such as PPC and ARM, and one you can run on baremetal RPi:
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.
19 comments
[ 1.4 ms ] story [ 70.0 ms ] threadThe 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.
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
(and NEXT is) This won't really be blazing fast, or will it?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'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.
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.
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.
http://www.lshift.net/blog/2007/10/04/jonesforth-ported-to-p... https://github.com/M2IHP13-admin/JonesForth-arm https://github.com/phf/forth https://github.com/organix/pijFORTHos
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.