/r/Forth

Photograph via snooOG

"In particular you need to avoid writing code for situations that will never arise in practice. You need to avoid writing code to handle a general problem that you are never going to encounter. I don't need to solve the general problem when I only have to solve these specific cases." -- Chuck Moore

Why Forth?

  1. You can try things out interactively as you build your system. The compiling functionality is an exposed part of the language like everything else.

  2. It can be used to debug itself!

  3. Forth has no baked-in syntax or privileged data structures -- programming is done by extending the language to your application. Thus, it can become what ever you need it to be and fit the problem like a glove.

  4. Forth has a "low floor; high ceiling" approach to abstraction -- that is, it can be both low level, high level and anywhere in-between.

  5. You can do more with less. Forth fits in very small storage spaces.

  6. Forth is one of the few environments which is totally comprehensible by one person.


/r/Forth wiki


Tutorials

Starting Forth - A fun, illustrated introduction.

A Beginner's Guide to Forth - A faster-paced, somewhat less whimsical guide.

Forth Lessons

Jonesforth - How to write a Forth.


Documentation

ANS Forth standard

Forth 200x


Reading

Thinking Forth - A Language and Philosophy for Solving Problems

Forthwrite Magazine - From FIG UK.

Forth Dimensions - magazine archive.

The Journal of Forth Application and Research


Community

comp.lang.forth - Forth newsgroup.

#forth in irc.freenode.net

ForthHub community on GitHub


See also

/r/concatenative - Anything related to the use, theory, or implementation of concatenative programming languages.

/r/programbattles - Battle it out between likeminded coders to create the best code possible!

/r/Forth

3,561 Subscribers

13

zeptoforth 1.10.0 is almost here

It has been a while since there has been a zeptoforth release, but a new release will be coming very shortly, probably within a week. This new release will contain a new USB CDC console driver for the RP2040 and RP2350, which fixes the reliability problems that were present with the old USB CDC console driver on the RP2350. It also will contain important updates to zeptoIP and the CYW43439 driver, including a rewrite of the circular buffers for storing frames such that it now makes far more efficient use of circular buffer space (such that if one so desires one can now actually get away with shrinking the circular buffers used by the CYW43439 driver at compile time in order to save RAM space, which is at a premium on the RP2040), along with an important fix to an issue where zeptoIP would die if you sent it a 1500 byte ICMP ping packet.

If you do not want to wait for the release, go ahead and git clone https://github.com/tabemann/zeptoforth.git, or if you have done so, git pull in the master branch, and build it locally. The only things that are not yet in the master branch are some contributed code in the devel branch which is currently being worked on (but is not relevant unless you want to use particular peripherals, specifically the LCD1602).

You will need a USB-serial dongle to do so, mind you, and under Windows you may have to manually install pySerial with pip and directly call the Python build scripts (because under Linux they are normally wrapped in shell scripts that provide conveniences not available under Windows).

Note, however, that you will be able to use the previous version's zeptoforth kernel for this purpose (so you will not need to install the arm-none-eabi toolchain or make), which can be gotten from bin/1.9.1/<platform>/zeptoforth_kernel-1.9.1.uf2 on the RP2040 and RP2350 and bin/1.9.1/<platform>/zeptoforth_kernel-1.9.1.bin on the STM32* platforms from https://github.com/tabemann/zeptoforth/releases/download/v1.9.1/zeptoforth-1.9.1.tar.gz as there have been no kernel changes. (The only effect of this will that the version number will read 1.9.1 and the build time/date will be that for the 1.9.1 release on bootup.)

1 Comment
2025/02/03
16:02 UTC

8

8th ver. 25.02 released

This is a bug-fix release, since a couple relatively important bugs were fixed.

Details on the forum

0 Comments
2025/02/03
06:27 UTC

29

A Forth for gamedev - early access

Recently I came across some retro gaming platforms like the TIC-80 tiny computer (or its commercial counterpart, PICO-8) and lightweight game engines like Love2D.

Originally, I expected a simple virtual machine, but then I realized these are just applications that can be scripted in Lua.

Although Lua is a cool little language, it doesn't have any "retro feel" to me. So, I created a Forth compiler in Lua, which makes it possible to write simple games in Forth and run them on Lua.

The Love2D integration already works, and the TIC-80 support will come in the future.

Although retro game development was the main inspiration for the project, it can be used anywhere Lua works.

The simplest way to install it is by using Lua's package manager, called luarocks.

$ sudo luarocks install equinox

I tested it on Linux, but it's still in the early stages. Please let me know if anything doesn't work.

Here is the project's github page.

11 Comments
2025/01/30
11:18 UTC

3

Convert Float from Stack to String

How would you go about this. Assume there is a floating point stack and that you don't know the form of the number.

I know Gforth has a word (https://www.complang.tuwien.ac.at/forth/gforth/Docs-html-history/0.6.2/Formatted-numeric-output.html) but what if you didn't?

5 Comments
2025/01/21
14:52 UTC

10

Early Beta: Forth for the ULP

I have been working on an optimizing Forth cross compiler for the ESP32 ULP coprocessor, an interesting processor because it has a decent simple instruction set but only four registers. It is a normal Forth interpreter/compiler written in Go, which can then optimize and cross compile the output for the ULP. This has both token threaded and subroutine threaded backends. I haven't tried to but I don't think it would be very difficult to port this to another computer. If there is an interest in adding multiple backends, I may reorganize a few things to make it easier for porting.

If you are interested please try it out, I'm going to continue working on it but would love any and all feedback. There is access to most of the standard Forth 2020 words, full GPIO access, bitbanged serial output and i2c, shared memory with the ESP32, and more.

https://github.com/Molorius/ulp-forth

9 Comments
2025/01/20
23:37 UTC

4

Help me diagnose a bug in a short snippet

I am confused as to why my Forth program, using gforth, causes an infinite loop of stars to be printed without newlines.

My expected output is:

*
**
***
****
*****
******
*******
********
*********
**********

Code:

: STARS 0 DO 42 EMIT LOOP ;
: TRIANGLE 0 DO I STARS CR LOOP ;

10 TRIANGLE
6 Comments
2025/01/20
15:07 UTC

18

Is POSTPONE the Forth's analog of Lisp's quote?

I’m a Lisper trying to understand Forth's metaprogramming. From my understanding, POSTPONE in Forth seems to serve a similar role to quote in Lisp, as both allow you to defer the evaluation of code.

10 Comments
2025/01/18
19:52 UTC

5

lina64 on FreeBSD

The ciforth model is now ported to FreeBSD 64 bits. See the announcement in r/freebsd.

3 Comments
2025/01/17
14:16 UTC

10

"8th" version 25.01 released!

iOS fully supported (and both iOS and Android sample apps are in the respective stores).

Lots of fixes as usual, as well as various enhancements. Full details on the forum.

0 Comments
2025/01/15
10:58 UTC

6

Standards

As someone who didn’t grow up with Forth, I see two standards and I wonder if it matters which one should be implemented or (parts of) both or “who cares?”

https://forth-standard.org

https://www.taygeta.com/forth/dpans.html

It seems like it might be important if a word like WORD or FIND have different arguments and returns. Probably several other differences…

Am I overthinking it?

10 Comments
2025/01/13
20:25 UTC

7

Multiple lexicons?

Hello.

I'm currently crunching through "Thinking Forth". The author often mentions "lexicons", in plural. E.g.: "Instead, each lexicon is free to use all of the commands beneath it.".

Now I'm wondering. Is a lexicon something like a namespace or package in other languages? How does one create multiple lexicons? Or is this just a metaphor and means: use a word prefix to separate words in namespaces within one lexicon. (btw: I'm on JForth on Amiga and I haven't seen a mention of how one could create other lexicons in the documentation).

9 Comments
2025/01/10
09:41 UTC

4

Something FORTHwrights might be interested in.

Meet Just. The technical term for it is a "task runner," but the author also describes it as a leaner version of Make. What it allows you to do, however, is put a list of maketargets in a file, (the author calls them "tasks") and then invoke them individually via either name or alias from the command line.

What this means is that you can write ifless branching, by specifying a list of numerics, and making each number an alias for a function. Then you just make each function set a state variable to the number address of one of those functions, and re-iterate. You can keep endlessly bouncing around any specific dictionary.

4 Comments
2025/01/10
07:08 UTC

22

What Differences are there in DSLs in Forth vs in Lisp?

In both families, you should grow a language for your domain.

In Lisp (especially Racket), this is quite explicit or formalized, with luminaries preaching about Language Driven Development etc. There are also extensive (if often older) code bases to peruse.

In Forth, this is sometimes more bare bones e.g. in /u/bfox9900 's Cosmic Coquest game where some words start with j show they're parts of the "j structure". I've seen precious little on program design, architecture, maintainability and so on though. Thinking Forth e.g. focuses on how to make a DSL to tackle your problem, how e.g. automated testing etc. help you there, but doesn't discuss maintainability or how to deal with the problem space evolving. For fear of writing Lisp in, well, Factor, what distinct considerations etc. must we account for in Forth?

4 Comments
2025/01/08
22:24 UTC

13

Embedding Forth in other languages?

I was wondering if anyone is interested in using Forth as an embedded scripting/config language for applications, similarly to how Emacs uses ELisp or other programs use Lua. I tried to search for this, but of course you can predict what sort of results you get if you search 'embedded forth'.

it seems like the Forth community generally prefers things be very low level (insert funny quote from Moore about how operating systems are useless), so i think most Forthers would prefer to just do everything from within Forth itself, rather than extend an application with it.

Thoughts?

20 Comments
2025/01/06
20:27 UTC

5

VFX Forth and Windows Defender

Do any other VFX Forth users exist on here? Have you run into Windows Defender false positives with your turnkeys and how do you deal with it?

8 Comments
2025/01/04
15:04 UTC

20

FreeBSD and Forth

I have recently installed FreeBSD on my HP Z840 workstation. To my surprise there were a lot of startup scripts written in Forth until version 12. Now they are written in lua, and some files are more compact. The 32 bit linux ciforth (lina32) works on FreeBSD 14.1 , See the announcement in r/freebsd

12 Comments
2024/12/28
12:34 UTC

8

Mounting and testing a LoRa transmitter

https://eforthwin.arduino-forth.com/article/examples_lora_transmetteurLoRa

LoRa transmission is the choice offering the best compromise between reliability and transmission distance. Where WiFi covers a distance of 30 to 60 meters, LoRa offers a range exceeding several kilometers. Here, we will interface a LoRa transmitter to the USB port of a PC, then manage this transmitter in Forth language.

https://preview.redd.it/74ydvik7o29e1.jpg?width=500&format=pjpg&auto=webp&s=d9c631020fd100be71841b64f3d03c4a8a7a7b44

0 Comments
2024/12/25
22:38 UTC

10

How to print name of word current executing

Hello.

I'm on an older Forth (JForth on Amiga). But it should conform to a mixture of '79 and '83 and FIG.

I'm wondering how is it possible to print (or find out without printing) the name of the word that is currently executing?

21 Comments
2024/12/19
19:10 UTC

6

COMx: serial transmit and receive

https://eforthwin.arduino-forth.com/article/examples_serial_serialTRandRC

During the Forth developments using the serial link, some small problems appeared that had to be fixed. Rather than correcting and completing the previous chapter, I preferred to explain here the evolutions of the code managing the serial port.

https://preview.redd.it/qt7nsxboet7e1.jpg?width=600&format=pjpg&auto=webp&s=917bf2d2e161b4bc4e82f28638e79f1ab21f0c4b

0 Comments
2024/12/19
14:24 UTC

9

Orchestration (DAGs) with Forth.

Background

Like many Forth users, I am a veteran of 1980s home computing. I had an upgraded Dragon 32 with 128K RAM, 2 disk drives, OS-9, a Forth "Development Environment" (if you can call it that!) and an 80 column display. This was a fairly popular upgrade in the late 80s. I enjoyed Forth, but I stopped using it after I went to university and the focus changed to Pascal.

Now

I have a relatively complex life as befits a person in their 50s trying to hold together various responsibilities, including managing accounts for various entities. I use ledger-cli which requires various inputs (APIs etc) that I wish to automate. It's a collection of command-line tools, bash scripts, perl scripts etc. At present I run these manually and add the output to my ledger-cli ledgers.

I have been looking into various DAG-based orchestration tools such as Airflow but it seems insane to orchestrate my scripts using something so enormous.

I have been playing around with gforth simply for nostalgia's sake when it hit me: perhaps I could use it to orchestrate my ledger scripts. I could build up a dictionary of words that allow me to define and run a DAG using Forth.

Is this something anyone here has had a go at? Or am I barking up some completely crazily wrong tree here?

4 Comments
2024/12/18
05:14 UTC

14

App built with "8th"

I've released the first version (well, the second...) of my "zemanim" calculator app, for all the platforms 8th currently supports (iOS missing still, coming soon).

Includes the source code for those who are curious what a full-blown app in 8th might look like.

6 Comments
2024/12/13
11:13 UTC

12

"8th" version 24.08 is released!

Our final release for 2024!

Tons of fixes and improvements, ]details on the forum](https://8th-dev.com/forum/index.php?topic=2926.0).

Also began our year-end sale, through New-Years Day.

0 Comments
2024/12/12
17:29 UTC

9

Introducing sw

Hi all,

I've been working on a custom Forth interpreter in Swift for a while now. It can't do much beyond fibonacci yet but the codebase should be relatively approachable.

https://github.com/codr7/sw

2 Comments
2024/12/12
15:42 UTC

5

Debugger

Before I continue, I want to give a shout out to r/spelc for his awesome VFX Forth. It's been truly an inspiration to me, but I want to assure him that I am not using it to leach concepts from. My Forth is my own work. I'm not using or even looking at any of the VFX forth sources that come with the product. It's unfortunate for me because there's many man years' of innovation that I'm going to maybe have to implement on my own. I also want to assure him that I respect his intellectual property utmost.

It's gotten to the point where bochs' debugger is not so useful since it doesn't know how to find symbols in the dictionary - it's all just a bunch of hex addresses.

So I'm implementing my own debugger.

I intend to use the TRACE bit, debug registers, software breakpoints, and INT3/INT1 instructions. I'm trying to write as much of the debugger in Forth as possible, but it's a strange environment. The breakpoint instruction causes an exception, and the exception handler saves the state of the current task (my Forth has true multitasking, see the output of the PS word in the screenshot) and sets up a fake Forth environment so words can "sort of" be defined and execute. For example, I have a dedicated data and return stack for the debugger - it's not using the current Task's environment because the whole idea is to be able to examine that environment without cruft added by the debugger.

While debugging, stepping, running until breakpoints, etc., the context will be switching between debugger context and freely running multitasking system/Forth. Implementation of "step out" is going to be something like:

  1. set trace bit

  2. return to Forth

  3. trace handler checks for RET instruction and does a single step if found

  4. otherwise go back to step 1

Something the debugger has to do is to save the byte of the instruction at a breakpoint and replace it with an int3 instruction. When the breakpoint is hit, the bytes saved need to be restored. When execution is continued, those breakpoint bytes need to be restored. So call it "enter" and "leave" the debugger. I may end up having the debugger save and restore more than breakpoints - perhaps intercepting certain DEFERed words like QUIT and ABORT so calling those return properly to the debugger instead of to the Forth inner loop.

This scheme for my debugger is somewhat problematic because not all the base Forth words I've defined work as expected. For example, .S (print stack) will print the task's stack, not the debugger's and the debugger's stack is important to be able to view. The debugger commands currently have the form: ```<COUNT> command``` as in ```10 step``` or ```10 disassemble```. But using the regular dictionary is important for inspecting things - ```SEE someword```.

It's also problematic because I'm ending up writing my own Debugger.Quit, Debugger.Accept, Debugger.Interpret, and so on. I'm thinking that I may use a FLAGS bit in the dictionary structure to indicate words that can be called from debugger context. Some words like + and - and * and NOT obviously need to be callable.

It's also possible to fully implement the debugger in assembly language, but I would be incrementally adding functionality where existing Forth words already provide that functionality.

Here's what it looks like so far:

https://preview.redd.it/1osv4wkn946e1.png?width=795&format=png&auto=webp&s=a98283b5910341bd0f4b187e990b29ac32417edb

4 Comments
2024/12/11
01:10 UTC

20

Figured out DOES> finally

This concept made my brain hurt. I made a feature branch to implement it a few times before tossing them.

The more I work on my Forth implementation, the more building block words I have to implement new concepts.

My Forth is STC for X86/64. A long time ago, I made the dictionary header have a CFA field that my assembly macros and CREATE words automatically fill in to point at the STC code. INTERPRET finds a word and calls >CFA to decide to call it, compile it inline, or compile a call to it.

For DOES>, I compile in a call to (DOES) and a RET. The RET ends the CREATE portion of the defining word. After the RET is the DOES part of the word (runtime). (DOES) compiles a call to the LATEST's >CFA and then stores the address of the RUNTIME in the CFA field. So code that call the defined word does something like "call word, word calls old CFA to do the DOVAR or whatever, and then jumps to the RUNTIME.

It's not super hard, but it took a lot of trial and error and debugging to see the state of things at define, create, and run times.

To clarify things a bit, here's the defining word X and using it to define Z and executing Z. It works as expected. For clarity, x is defined as : x create , does> @ ;

I haven't tested it beyond what you see, but I think multiple DOES> is going to work find, too. Due to the handy chaining of words property of the dictionary, each DOES> will call the old CFA which is the previous DOES> and it should work. I'll test it at some point (I'm having too much fun expanding the functionality vs. writing tests.

Here's the source to DOES> and (DOES). Being an STC Forth, many of my words are designed to generate machine code versus generating call, call, call type threads.

https://preview.redd.it/dn6rb83j746e1.png?width=974&format=png&auto=webp&s=c26e785d7ae563bab3ce634a4e6d7304de13c07c

https://preview.redd.it/f0g2defn746e1.png?width=963&format=png&auto=webp&s=e5931bcb852efe4f4c957a0fa257377c096c81a8

https://preview.redd.it/60ehsxxw646e1.png?width=740&format=png&auto=webp&s=9b3f6e42632becd34ae541dddd5aea8e54b774a4

14 Comments
2024/12/11
00:38 UTC

4

Evolution of structures since version 7.0.7.21

Structure management has just undergone a major facelift in version 7.0.7.21 of eForth. Discover the new feature that makes managing fields in a structure much simpler.

https://eforthwin.arduino-forth.com/article/elements_evolStructures

https://preview.redd.it/r22o70nc8w5e1.png?width=902&format=png&auto=webp&s=4036f42684f6975d55179385852ef032aa85b266

5 Comments
2024/12/09
21:46 UTC

12

zeptoforth 1.9.1 is out

zeptoforth 1.9.1 has been released. This release renames the int-io module to serial (the old, now-deprecated int-io name is retained for the time being but will be removed in a future release), fixes a major timing issue with the CYW43439 driver on the Raspberry Pi Pico 2 W, and fixes a number of numeric literal parsing issues. You can get it from https://github.com/tabemann/zeptoforth/releases/tag/v1.9.1.

Note that there are issues with the USB CDC driver on the RP2350 which make it difficult to reliably upload the CYW43439 firmware, the CYW43439 driver, and zeptoIP to the Raspberry Pi Pico 2 W with it. Consequently it is highly recommended one use the serial console for this purpose. If one is using a full_usb build one can temporarily switch to the serial console with serial::serial-console.

0 Comments
2024/12/08
17:46 UTC

5

My4TH and AHT10 i2c temp sensor

Hello!

So, I've built a My4TH board, it's got a 16 bit Forth 2012 implementation on it, and it's pretty sweet. Because it has an onboard i2c interface, I've been trying to talk to an AHT10 temperature sensor, and I've got it going! But now I'm unsure how to do the math. So I run the word:

Terminal ready
  ok 
aht10  ok
hex  ok
. 11  ok
. C8  ok
. 5  ok
.  ? stack

So I'm getting 5C811 out of the sensor. The formula to get the result in degrees Celcius would be: (value / 2^20) * 200 - 50, and if we run the math, I'm getting (378897/1048576) * 200 - 50 = 22.26! So I'm getting valid data, and the math works, but I'm a bit unsure how I'd go about that. So assuming you've got those values on the stack, how to calculate?

Thanks in advance, this is my first foray into Forth on a small machine, and it's pretty cool!

9 Comments
2024/12/05
21:03 UTC

Back To Top