A few years ago I wrote a literate FORTH compiler and tutorial called JONESFORTH. It’s a good way, I think, to understand the power and limitations of FORTH, and a good way to learn a completely different and mind-blowing programming language.
If you’ve not heard of FORTH before, cogitate on this: It is possible to write a FORTH program in 2,000 lines. A program which will boot and provide an entire development environment (inc. editor, compiler etc) on bare hardware.
Anyhow, I just uploaded my semi-private CVS repository to git. You can find it here:
The original tutorial is in two parts:
52 responses to “JONESFORTH git repository”
thanks for your fantastic work.
I’m using it as a starting point in my next project. It will be used as a vm of a compiler.
According to the work of Richard Russell on bb4wforth, version 47 of jonesforth has a bug in /MOD which is easy to fix. The fix proposed by Richard is
push %edx // push remainder
push %eax // push quotient
Another fix is the U. in file jonesforth.f which should uses U/MOD instead of /MOD. The proposed change of Richard is to add U/MOD to jonesforth.S and to modify the U. accordingly.
xor %edx, %edx
push %edx // push remainder
push %eax // push quotient
: U. ( u — )
BASE @ U/MOD ( width rem quot )
?DUP IF ( if quotient 0 then )
RECURSE ( print the quotient )
( print the remainder )
DUP 10 < IF
'0' ( decimal digits 0..9 )
10 – ( hex and beyond digits A..Z )
Will you fix this bugs in the git respository?
Do you accept any patch?
Execute me, the length of U/MOD is 5, not 4.
According to Richard’s work, jonesforth’s implementations of /MOD and U. have bugs, implementations of DEPTH, .S, HERE, ALLOT, CREATE, VARIABLE, TRUE, FIND, WHILE, REPEAT, WORD, KEY and ‘ are not compliance with ANS Forth. I’m planning to change these and only these, to keep jonesforth’s minimalism and to pave the way for ANS Forth compliance.
In other words, to make ANS Forth a natural extension of jonesforth.
If you agree, I can send you my patch after I have finished it.
What I suggest you (and anyone else) do is to set up a git repo and/or website with whatever changes you want to make. Let me know about the new site and I’ll add a link to it on the main website.
yes, I’ve set up a git repo at github.
My first move is to remove/reimplement the inconsistent part of jonesforth. Please see the non-standard core word section in TODO to know what I’ve done.
Interesting to see your attempts Cheng-Chang Wu,
do you have a contact e-mail?
Pingback: Daniel’s Stuff » The Funky Clock
Hi Rich. The annexia links are broken.
You can still grab the source from
This : http://git.annexia.org/?p=jonesforth.git;a=summary
links are broken .
Please check it.
Seems to be working fine, albeit slowly, for me.
git://git.annexia.org/git/jonesforth.git <– I can't clone from this URL 😦
It should work now. Debian (or git) changed the way git-daemon works so now the git directory has to contain the empty file
git-daemon-export-okotherwise it refuses to allow people to clone it.
Still not working 😦
[tesla:~/Source] git clone git://git.annexia.org/git/jonesforth.git
Cloning into jonesforth…
git.annexia.org[0: 220.127.116.11]: errno=Operation timed out
fatal: unable to connect a socket (Operation timed out)
OK so the hosting place lost power over this holiday weekend, and the machine didn’t come back up. It’s working now.
Awesome, it worked. Made a GitHub mirror here: https://github.com/nornagon/jonesforth
Hi guys, just checking in. Glad to see fresh FORTH faces. 40+ years a FORTH-er here. Anyone into colorFORTH and the new greenarrays chip? Hairy stuff! Cheers, Clyde
I’ve been porting JonesForth.S and JonesForth.f to Windows.
Are you interested in reviewing my work before I publish it?
I’m not sure I would know what to review for a Windows port, so I suggest publish away.
Let us know when you have decided and what we can do to assist you.
I suppose I should have been more specific about what I thought Rich might want to review. Specifically, his tutorial prose has been significantly edited and so I wanted Rich to have an opportunity to see those changes before publication. I am still in the process of making the system more ANS compliant, so I’m not yet ready to publish. However, if anyone would like an advance copy, please drop me a note: mailto:firstname.lastname@example.org
I’d say just go ahead and publish. It’s public domain after all — designed to be distributed with the least friction possible.
Ok, Forth Fans:
This isn’t the finished version, but something I hope will generate some buzz.
Almost 10 years later (and, according to http://www.dst-corp.com/james/, unfortunately too late for Mr. Larson to see it), I decided to take a crack of my own at translating JonesForth to C. Because I wanted to delve into the details, I chose not to use the asm keyword. You can read about it and even interact with it here:
Hello Jan, is there a link to your code? I couldn’t see one in your blog entry?
I had some trouble running this, but once I followed the comment by Arto Bendiken posted at http://subvert-the-dominant-paradigm.net/blog/?p=54, “make test” works fine.
“Note that if you attempt to run this on recent versions of Linux and the program simply aborts and prints out “Killed”, you will need to recompile without the “-Wl,-Ttext,0″ option to GCC.”
Thanks — I wonder what changed. Note that we do assume the text starts at address zero.
This behaviour is caused by SELinux. It is trapping the attempted access of zero page. Just ran into it myself. It’s possible to add an exception, or just switch off SELinux… though the path of least resistance is probably to move the start address up.
That’s annoying to say the least! I guess this is related to the new execmem stuff that SELinux is controlling.
This may have nothing to do with SELinux. Newer Linux kernels have a feature which allows to protect an area of low virtual memory from userspace allocation (configured by CONFIG_DEFAULT_MMAP_MIN_ADDR), which can help reduce the impact of kernel NULL pointer bugs.
Get (or change) the current value by reading (or writing) /proc/sys/vm/mmap_min_addr
On my system, `cat /proc/sys/vm/mmap_min_addr` returns 4096, so I updated the linker options to `-Wl,-Ttext,1000` (note: the address must be specified in hex!), and everything works well.
Pingback: regular expressions - Page 8
Hi – I am new to FORTH and just found your FORTH the other day. Like how it is commented so well. I would like to implement it on a Microchip PIC24 computer. The PIC series is Harvard architecture with code in flash and data in ram so it may not be possible to implement assembly code in ram as all code goes into flash. I may be all wet in this and have not thought it fully out. I guess since much of FORTH is written in FORTH the assembler instructions could be in flash and the FORTH added words could be in ram. Any ideas you have would be greatly appreciated.
It does look as if this chip was not designed to fetch instructions from RAM, and therefore you’d have trouble compiling assembly or inline words and running them (on any FORTH). I believe that compiled high level words would be OK. It would be fun finding out.
Good luck anyway!
Being a REAL NEWBIE at this it looks to me that the core forth has words with code modules that can be branched to. Then the rest of the system is in character FORTH words which could be put in ram. Is that true? That may work on a Harvard arch.
Any ordinary words don’t require running machine code from RAM, eg:
;CODEwords would, eg:
Also any word using
C,would be suspicious (but not necessarily a problem).
This only applies to the interpreted FORTH code. Any primitives are fine because they live in the assembled text segment which would be stored in the Flash ROM.
Hi I’ve just discovered Jonesforth and wanted to say thank you for writing & releasing it, it’s a really great introduction into forth implementation.
I wanted to make one remark about a comment in the sources: you mention the “strange forth convention” that “the comparison words should return all (binary) 1’s for TRUE and all 0’s for FALSE”.
I think the reason for this convention is that so that the words AND, OR, XOR and INVERT can function both as logical operators and as bitwise operators.
By comparison, with the C convention that FALSE = 0 and TRUE = 1, you need two sets of operators: && and &, || and |, etc..
So there is method to the strangeness.
Hi, thanks for this great work!
One question, the “standard-fixed” versions also mention that while/repeat were not originally standard compliant. I am curious in what cases the existing implementation was wrong? I have been using it a lot and it seems to work fine for my purposes 🙂
I don’t know, but ANS FORTH (1994) is downloadable, eg from here. The WHILE statement is defined in section 6.1.2430. JONESFORTH doesn’t follow ANS “religiously” — for example truth values follow C style, not FORTH style.
There is a nice HTML version (with hyperlinked chapters) here: http://www.complang.tuwien.ac.at/forth/dpans-html/dpans.htm
I’ve translated JONESFORTH to Swift. The code is available here for anyone who wants it: https://github.com/kristopherjohnson/suwaneeforth
Implementing an old low-level language in a new high-level language is a strange thing to do, but it was fun and educational. Thank you for providing something to study.
These links seem to be broken, could you please re-upload them somewhere?
Umm, link is in the article .. http://git.annexia.org/?p=jonesforth.git;a=summary
I’ve tried making the project on Ubuntu 14.04. It gets link errors indicating undefined references to __NR_open and __NR_creat. Someone else noticed the problem a couple of years ago – see http://paste.lisp.org/display/137373 – but I’m not smart enough yet to figure out what’s going on. Any thoughts?
__NR_*are system call numbers. They depend on your architecture, but can be found in the source of the Linux kernel and (previously) in the header files although apparently not any more. See
include/uapi/asm-generic/unistd.hin the kernel source.
Yeah, to make the thing assemble at all, I had to make /usr/include/asm a symbolic link to /usr/include/asm-generic. But it turns out that within asm/unistd.h, the definitions of __NR_open and __NR_creat are now wrapped in #ifdefs. When I define __ARCH_WANT_SYSCALL_NO_AT and __ARCH_WANT_SYSCALL_DEPRECATED before the #include, the assembly works fine.
The resulting program doesn’t seem to work – I don’t see the welcome message, and terminal input seems to do nothing – but I guess that’s an opportunity for me to learn a little about gdb. 🙂
I’m on a 64-bit system, so asm/unistd.h provides 64-bit __NR_* system call numbers. When I commented out the #include and hand-coded the 32-bit call numbers for int 0x80, the program worked. Success! Thanks.
On Ubuntu (x86_64) I could get the required headers by installing linux-libc-dev:i386. That and removing the -Ttext made make test work for me.
I had been getting a segmentation fault when running jonesforth from the annexia repository. stackoverflow post about the issue and one possible solution:
Pingback: From Duskers to CHIP-8 – Perpetual Programmers
In regards to Forth running on the pic24/dspic; this implementation of forth allows an app/new word to run from ram for edit/testing/debugging purposes to reduce flash write/erase cycles. The resulting app/new word can then be transfered to flash.
Scroll to the bottom of the page.
Pingback: Jonesforth Port to RISC-V - JellyEnt
Pingback: Assembly Nights by jorangreef – HackTech News
Pingback: Assembly Nights