Browsing Forth

Forth has a strong following among embedded developers. There are a couple of reasons for that. Almost any computer can run Forth, even very small CPUs that would be a poor candidate for running programs written in C, much less host a full-blown development environment. At its core, Forth is very simple. Parse a word, look the word up in a dictionary. The dictionary either points to some machine language code or some more Forth words. Arguments and other things are generally carried on a stack. A lot of higher-level Forth constructs can be expressed in Forth, so if your Forth system reaches a certain level of maturity, it can suddenly become very powerful if you have enough memory to absorb those definitions.

If you want to experiment with Forth, you probably want to start learning it on a PC. There are several you can install, including gForth (the GNU offering). But sometimes that’s a barrier to have to install some complex software just to kick the tires on a system.

We have all kinds of other applications running in browsers now, why not Forth? After all, the system is simple enough that writing Forth in Javascript should be easy as pie. [Brendanator] did just that and even enhanced Forth to allow interoperability with Javascript. The code is on GitHub, but the real interesting part is that you can open a Web browser and use Forth.

If you want to learn Forth, you could do worse than start here. You can also use the Web browser-based Forth to try things as you read. If you want to create you own Forth, though, you really ought to read JONESFORTH. Not only is it a Forth system in two files (an assembly language file and a Forth file), but it is one of the best examples of literate programming we’ve ever seen.

In addition to a lot of older computers and–of course–the PC, you can find Forth for many modern processors. For example, we’ve seen systems for the LPC ARM chips. There’s even a version for the ESP8266 and the Arduino (see the video about that Forth, below).

46 thoughts on “Browsing Forth

  1. Honest question, not trolling….. I don’t know forth, but I know assembly on several ucontrollers and cpus, and prefer c for my micro work (knowing assembly helps optimize my c) so my question is, I don’t understand the statement: “even very small CPUs that would be a poor candidate for running programs written in C” followed by things are carriered on the stack, where that’s exactly what makes a good c micro. Because local vars are in the stack space, and when the function returns the stack is cleared. Can someone give me more info?

      1. I read through it, and I get the parts it explains, but I just dont see how one can be better than the other, I just see them as different. I look at language syntax as a trade off. That is, there will be a sum of work done, parts by the compiler/cpu and the parts by the end user. I wrote small interpreter for an 8bit chip where parts of the language were easier to parse and interpret for the interpreter, but created code that was not as human readable. the more human readable, the more word done by the cpu. So a 4 3 +, is simpler for the cpu/interpreter, I fail to see how its easier for the programmer. Just like in assembly, MOV AX, 0x10 is quick and easy to decode, even interpreted, but a new programmer would understand AX = 0x10 easier. in case anyone wants to play with the intepreter: http://www.mculabs.com/projects/fplCore.html

        1. Well, I disagree but you can read why in some of my other replies. Most Forth implementations don’t actually produce functional calls but do threaded code interpretation which–of course, like everything–eventually results in function calls, but they aren’t explicit. That’s why people get confused about interpretation of Forth. As another commenter pointed out, it is usually compiled, but not to native code. Instead it is compiled to tokens that identify either native code or more Forth tokens. That, combined with an interactive eval/print loop makes people think it is interpreted. If you are hanging your computer with Forth, you probably are hanging it with any other language that doesn’t have training wheels (e.g., C or assembly, but not Java).

    1. I agree, why not just use C as the Flying Spaghetti Monster always intended us to? I agree I’m not an expert, but so far haven’t found a micro controller that you can’t write C for – sure, it might sometimes be a subset , and cross compiled from another platform, put it’s still doing it in syntax that we understand as readily as our primary spoken language.

      And no, I’m not being sarcastic..

      1. Forth is both an interpreter and a compiler.

        The moment it breaks off a word from the input stream (by finding the whitespace), it looks it up and executes it, right then and there. Hence the need for the implicit data and return stacks, and the post-fix notation.

        This makes Forth unbeatable for exploratory coding on embedded systems, especially in laboratories where requirements for control systems can change suddenly – Forth’s original niche.

        Forth’s dictionary is a linked list: It’s trivial to add to it, and one can also trivially extend the compiler itself as well, with both new defining words as well as new compiling words. OO (if you want it) is a couple of lines away.

        Compiled words only do look-ups if you make them, otherwise they just use calls, using the return stack. You can control whether or not a newly-defined word is visible to itself in its own definition. You can redefine a word, calling the old definition anywhere within the new.

        There are well-documented standards too.

    2. They’re thinking of actually parsing and interpreting the source on the device itself (i.e. running via an interpreter). Just look at the context of where that statement appears – it compares Forth to not only C, but also to a full development environment (hardly a programming language!), then goes on to talk about interpreting it.

      In other words, the comparison to C is totally invalid. They’re basically comparing an interpreted language to running a compiler on a microcontroller, and then saying that since the compiler won’t work there the language doesn’t either!

      1. Until you take the time to see what Forth is this will all sound weird, but here goes.
        On a small micro-controller with Forth in 8K ROM and 8K of RAM, I can 1. Interpret Forth code 2. Compile Forth as new functions on the machine(threaded compiler) and then use them in other compiled functions 3. Load a small assembler (<2K binary) and write assembler code functions that can be interpreted by name or compiled with other functions. 4. interrogate/modify memory, variables and I/O ports interactively as needed like a debugger
        It is not JUST an interpreter.

        So this is why it is so handy on new silicon or new boards when you need to experiment and debug hardware before a C compiler is available for the machine. You can also think of Forth as a 2 stack virtual machine when it's running on a regular computer. But has also been implemented in Silicon as a CPU and is out in space in the Galileo space probe in that form. For those things a C compiler can emit Forth binary code if you want to write in C for it.

        Original Forth systems compiled to threaded code, modern commercial compilers create native code like a C compiler would do.

        Forth is an alternate way to think about programming and so like LISP, APL Prologue and many others is worth some study by a coding practitioner even it you never have a use for it. Bottom line, in skilled hands it is ideal for programming in resource constrained environments but there are also million-line+ applications out there running on big OSes too.

        For many Forth makes programming easier for engineering purposes because you program by extending the language and even the compiler itself. In the end you are programming in a little language that you created just for the problem at hand. The freedom is pretty cool.

        1. Excellent description of the Forth software development approach! At some FIG meetings I began attending in 1977 I heard some call it a “programmer amplifier”.

    3. Forth is very simple, the core can easily be written, and run, with few resources. C at the very least would likely need to be run on another computer, the output running on the limited computer.

      Forth is an interpreter, so it gives resources on the end computer. In the very old days, a computer would come with a monitor, hopefully in ROM, that let you do endless things like feed in bytes to the memory, single step a program, display results. The Apple II monitor even included a mini-assembler and disassembler.

      Then most of that got wiped away, BASIC being in ROM and providing something to do when you got the computer home.

      FORTH is in between, a higher level language but it can also do the basics. It’s extensible, so you can write those monitor functions in it. We didn’t hear much about FORTH till around 1980, and I remember thinking how great it would have been to have FORTH in ROM. The Jupiter ACE from the UK was like a Sinclair zx-81, but ran FORTH.
      For a later while, some computers had a boot loader in FORTH.

      You could add a compiler, if the interpreter wasn’t fast enough. Or write an assembler in FORTH to get the machine code bits you did need.

      I’ve never run FORTH, never getting around to it and then later computers were so much better, little need. It would take some adjustment, not just because it’s RPN, but it seems a foreign concept. It took some time to wrap my head around it, I think I grasp it better now, but it’s not because I’ve explored that much.

      Michael

      1. I remember messing with a Jupiter Ace in the 80s it was certainly not intuitive thats for sure. There was also White Lightning which was a mixture of Forth and its own language. I actually think they should have just given us a built in Assembler and editor in these machines or the larger memory (above 1k) machines that followed.

      2. Michael, you really should try using Forth — BTW the name FORTH is trademarked by Forth, Inc; all other versions of Forth language implementation should not use that name capitalized.

        Re “Forth is an interpreter”, this is only partly true — in most cases of a Forth implementation there are actually two interpreters involved, the so-called inner and outer interpreters.

        The outer interpreter exists usually only in a host computer used to write and edit Forth code, although some embedded implementations include an outer interpreter for interactive control, source code compiling, viewing results, etc, using a terminal or computer via a serial port or other I/O like BlueTooth, HDMI, etc.

        The inner interpreter actually “executes” a running Forth application. It follows through a list like a command line in DOS, for example. See e.g. https://en.wikipedia.org/wiki/Threaded_code#Direct_threading

        In “indirectly threaded” Forth, before each action in that list is “executed” the inner interpreter pushes a physical address to a stack called the “return stack” and tells the CPU to do the action at that place in the list. When a list action is completed, the inner interpreter pops the return stack and advances its pointer to the next item in the list.

        In “directly threaded”, “subroutine threaded”, and other varieties like “token threading” the list processing is different. See e.g. https://github.com/mikaelpatel/Arduino-FVM

        Note, however that the list pointer may have been modified by the action just completed. For example, if the last action was a “branching word” like WHILE, UNTIL, IF or REPEAT, CASEIF, OF, then the outer interpreter may have jumped the pointer to a place in the list corresponding to where an ENDIF, ELSE, ELSEIF, ENDOF or BEGIN was in the source code. Also the action may have been to do something with a string of characters or push a number to the so-called “data stack’, so that string’s or number’s bytes needed to be skipped by in the list to reach the next action of the list.

        So, a running Forth program simply goes through a top level list, performing its actions, which themselves are lists to do when they are Forth “words”, but obviously all this kind of list processing must actually execute some machine instructions by the CPU. That happens at the so-called “leaves” of the tree of lists, which are so-called Forth “code words”; i.e. their “action” is to jump to an address where the outer interpreter “compiled” assembler code, usually using a Forth based assembler (written in Forth), although to begin with there had to be a “chicken before the egg” involving a “regular” assembler or C compiler, for example. On the other hand, there have been many cross-compilers, also called meta and target compilers, entirely written in Forth only!

        For the outer interpreter the “list” of things to do by a “compiled” or so-called “high level” Forth “word” is given a name in the source code and looks like a sentence which begins with a colon followed by the word’s name, then a list of previously defined “words” and possibly numerical data or ASCII text to be compiled into the associated run time list, and finally semicolon the terminate the definition of things to do for that “word”.

        For “code words” in Forth source code, one tradition has been to start a line with CODE then proceed to list Forth assembler “words” that mimic “normal” assembler operators like MOV interspersed with mimics of operand and data naming, and then end with END-CODE (or ;CODE ). See e.g. https://www.complang.tuwien.ac.at/forth/gforth/Docs-html/Code-and-_003bcode.html#Code-and-_003bcode

        In early RPN-style assemblers written in Forth, operand representing symbols and data preceded the operand symbols, but it seems everybody nowadays writes Forth based assemblers using forward operand placing as with “normal” assemblers.

        So, Forth is certainly NOT just an interpreter, it can be anything you can imagine. In fact, there are object oriented Forth’s, AI packages, you name it!

    4. If you’ve ever ported a C compiler (I have, and I will confess I have not been able to grok enough to port gcc anywhere despite a few false starts) you will see that architecturally, you need a lot more than a stack to support C well. First, you need a stack you can index from. If you can’t write something like “MOV A,[SP+32]” in assembly you will be sorry. Not saying you can’t do it, but your generated code will be awful. You also need a certain amount of registers that don’t have a lot of limitations on their functions with respect to each other and a way to manage the heap (especially before the appearance of embedded libraries and better selection of library code in link steps). You also need enough memory to have a heap. Look at the low-end PIC 8-bit range. For years there was no C compiler for them and while you might be able to get a cross compiler now for some of the larger ones, there are limitations and the code is very poor compared to what you would do in assembly. There’s not much memory. Everything has to go through the D register (the accumulator). You don’t really have registers as much as reserved memory locations in the very limited RAM. FSR isn’t really a proper stack pointer so doing things like indexing on the stack is miserable.

      That last may be the real killer. On those PICs, accessing the top of the stack is simple. Every time you access further down the stack it is a huge penalty to do math on FSR which destroys your stack base, necessitating you to restore the stack so you get the right return address, etc. Can’t do that in a static variable either because of nested subroutine calls. So we’ll do it on the stack–oh… wait…. no… can’t do that either. :-)

      Then there is the development environment, too. You can cross develop C for just about any target assuming you don’t mind the generated code bloat (like with the low-end PICs). But you are not debugging insitu without gdb stubs and JTAG and the like.

      Anyone who would suggest I’m not a fan of C hasn’t read much of my writing. I love C. But I also recognize that the more tools I have the more problems I can solve. I like a hammer and maybe I could pound screws into wood with it. But it would be foolish to get unhappy if someone told me I should get a screwdriver for the task of putting screws in.

      I’m not looking for a resurgence of Forth to wipe the C scourge off the face of the Earth. But for the right jobs, it is awesome. Case in point: My one instruction 32-bit CPU. It could handle C and I’ve made a few attempts at porting gcc over to it. That’s a huge task, though and I’ve never managed it. There are other C compilers like clang and pcc I’ve looked at, but all have been pretty big tasks and I’ve never gotten motivated. However, it took a few hours to do a cross compiled Forth. And if I wanted to host Forth it might have taken me another 30 minutes to do that–there’s just no persistent storage on that machine, so the value for that is low.

      In that case, it isn’t that C isn’t a good fit for the machine. It actually is. It is the effort involved in porting the C compiler is huge but I can stand up a working Forth system in a few hours. Forth is an elegant and simple tool that is surprisingly powerful for its size and complexity.

    5. Most of Forth is written in Forth. Beyond the inner interpreter, which can be 2 instructions in ARM, the “outer” interpreter is also small. A core of words (functions or routines) are written in assembly and can be written in a very small space, after which new Forth words are just a string of addresses of more primitive words, so they are basically 16 bit tokens. As you code, very sophisticated functions are called with 16 bit pointers. The interpreter is what marches through this list, like a list of subroutines an assembly. It is all very compact and efficient and the flow control is part of the Forth words and easy to understand or extend – like add a CASE statement or Guarded Commands.

      The Rockwell AIM-65 had 1K RAM and a Forth ROM. People did a lot with it. The 4K expansion allowed huge programs for the time. A floppy controller and block file system fit in 1K or source code! Compiled, it was tiny.

      I recall a complete automated cryogenic fluorescence spectrometer and phosphorescence lifetime instrument in the early 1980s with a 6502 and 24K of RAM that ran the instrument, collected the data, and deconvolved multiple phosphorescence exponentials. The data (4096 12 bit data points) and all the software fit in the 24K. Also a floating point library that used an AMD9511 FPU. Oh, and the obligatory pair of 8″ floppies :-)

  2. “Starting FORTH” by Leo Brodie is a great book. It is very easy to read and written in an entertaining way. Having it available on line is a good help. FORTH is pretty powerful. Years ago (1994) we built a real time imaging system to sort fruit in a cannery. The brain was an RTX2000 FORTH engine and it could sort to colour, size and blemish at about 20 peach or pair halves per second. Not bad for a CPU running at 10MHz. There is a bit of info here on the RTX2000…
    http://soton.mpeforth.com/flag/jfar/vol6/no1/article1.pdf
    I still have a tube or two of these brand new chips, just 20+ years old :)

  3. I used to play around with STOIC (a FORTH variant) on my CP/M systems. It was a lot of fun. And I had a FORTH cartridge for the C64 that I played around with too, but it wasn’t as interesting. I did more in assembly on that system. That computer is long gone, but oddly enough, I still have the FORTH manual for it floating around here someplace.

  4. Hmmm….

    I’ve never payed any attention to Forth before. This inspired me to read a little about it. I have a little robot I built for my young daughter to play with. The hardware was easy but what to program it to do so that it is interesting… that is hard. I think I might put Forth on it and teach her!

  5. For forth on a MSP430 and ARM check out Mecrisp by Matthias Koch:

    http://mecrisp.sourceforge.net/

    It’s really incredible. The boards are cheap and on something like an STM32F4, honking fast.

    The big advantage to forth is that it is interactive. You can develop a device driver and test it at the same time that you’re writing it. That was Chuck Moore’s motivation. He was programming the Kitt Peak radiotelescope, the dishes on railroad cars, using a 1968 vintage minicomputer. Custom hardware, skimpy documentation and a machine with only 4-8k of memory.

    Forth does not need a debugger because you’re always able to interact with the interpreter. The firmware in Sun Microsystems boards was forth code that got run when you booted and took care of the configuration. That’s why the “ok” prompt.

    1. He was programming looms for Monsanto I think. Telescopes were later IIRC.

      Yeah, SUN and later also Apple among others used Openboot and openfirmware, which is Forth and lets you drop into outer interpreter during boot. The new Device Tree in Linux collects device information nearly the same way.

  6. Right tool for the right job. I’ve been meaning to put a FORTH on an old ATMEGA103 dev board for general use in my lab. An interactive environment to quickly hack up a H/W tool beats pushing compiled C to the board by a huge margin. Also, the efficient use of resources is nothing to sneeze at in small systems.

  7. A couple of commenters seem to be claiming that forth systems are interpreters. I could be misreading them, but for people unfamiliar with forth systems I think it’s important to be clear: while forth systems are certainly interactive and have an interpreter, definitions of forth words (procedures) are almost always compiled as they are read in. Forth programs run at close to machine code speed. (Usually a factor of ~2 slower due to the use of threaded code, but this can be made up for in other ways.) Forth is very close to the metal.

    It’s actually more complicated than this (of course!) because forth words (procedures) can themselves control the parsing and compilation process in ways that will make your head spin. This is part of what makes forth incredibly fun and powerful. Read Starting Forth and an implementation like JONESFORTH for more information.

  8. I’ll chime in and freely admit that I use FORTH professionally at work with a commercial version and it has paid for itself many times over… I find it delightfully interactive and productive, especially at the embedded level. I’m not a “guru” programmer by any means–rather in a position needing to design reliable HW and FW under deadlines for real products. I was lucky enough to grow up in the 8-bit era, with my first computer a ZX81 and learn how much could be done with limited resources…

    FORTH allows me to bring up and validate HW _extremely_ fast–I see my colleague stuck in this code-compile-link-download cycle to a LPC1115 with the C tools as I sit there and poke away at registers, watching my results in real-time on the same part at the console or on a scope. FORTH has allowed me to finally stomach ARMs and appreciate the cool things they can do. Above the driver level, FORTH lets you develop apps in a similar interactive way and can be as structured as you want if you’re coming from the C world–FORTH lets you make it the way you want. Learning FORTH will make you a better C or whatever programmer as it does push you to think in a logical, structured fashion. Admittedly the stack was a bit odd to digest, but once you understand what it’s doing, there is no issue. read “Starting Forth” and “Thinking Forth” for at the bare minimum a lucid treatise on programming style.

    FORTH can also give you assembly-level access if you like, or have as thick or thin of a veneer to your HW layer as you wish, but if you get into it on a smaller system it’ll make you wonder why you really need that 1.2GHz CPU on your Raspberry Pi 3 and excited to see what you can interactively coax that M0 or AVR do!

    I can program in C too and I don’t hate it, I have just discovered a better solution for ME–your mileage may vary but if you don’t make a concerted effort to learn where FORTH came from and what it’s really about, you’re really missing a unique and enlightening adventure that will carry over into whatever language if choice if you don’t decide to stay with FORTH.

    …And I just _love_ seeing that OK prompt beckoning me to interact, just like warm memories of the “K” on the ZX81…

  9. Grr. When you try to port Z80 figforth found on the net to an embedded Z80, and discover that Forth’s obnoxious ideas about a file system are deeply scattered throughout the code. (can’t do a cold boot without initializing DENSTY !)

  10. I’ve written Forth for micros from 6502, 65816, Z80, MSP430, ARM (LPC2148 with VGA), many others, and in the last few years for the Parallax Propeller chip where it really excels. I’ve made mine fully interactive so that you can do the same thing in an interactive line that you can in complied Forth, that is, DO LOOP, BEGIN AGAIN, IF THEN, etc. But the thing is you can run it on multiple cores and it is very fast. As a lark the other day I wrote a WS2812 RGB driver in one line of code, complete with the sub-microsecond timing, all in high level Forth, no assembly. Because it is so productive it is a lot of fun.
    : WS2812 ( ggrrbb pin — ) DUP PIN L MASK SWAP 8 REV 24 FOR H SHROUT L NEXT 2DROP ;

    Since I use these in heavy duty commercial designs these are complete system Forths, that is, they have the necessary drivers for Ethernet servers, RS485 networks, serial ports, FAT32 virtual memory, and the list goes on and on.

  11. Back in the 90’s I worked on building a couple of audio consoles for the TV industry. These were built to allow for automation of setups and recall previous ones. Like many others who worked in the embedded industry FORTH was the logical choice as you had small processors and very specialized functions to preform. Being an extensible language FORT was the natural as the operations and functions were defined in a native state. This meant a very fast and minimalist set of code. They worked great and required very little support. New capabilities were very easy to roll out.

  12. The first time I tried to learn FORTH, I got the impression it was all about the RPN and the evaluation stack. The first chapters in my book were about the dozens of ways of juggling the stack such that arguments were in the right place for the next operation. I didn’t like it and dropped it (pun intended).

    I studied it again decades later, and the realised that all that stack juggling was merely a sign a poorly designed words. Most of it can be avoided once you’re aware of it. The emphasis in the text book shouldn’t be there at all. FORTH’s essence, and brilliance, is really the interaction between compilation and interpretation. It is much more like LISP-like in that regard than like a traditional Pascal/C/Java type of language.

    1. MvK, using RPN to arrange parameters saves compiling time wasted by processing of precedence rules and it makes you a better programmer by thinking through the steps and maybe even finding tricks to improve calculations. Good Forth programmers don’t juggle stack entries a whole lot.

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.