Show HN: I built a minimal Forth-like stack interpreter library in C
This weekend I created stacklib.h - a single-header library that brings Forth-style stack operations to C. It implements a basic interpreter with:
- Stack operations (push/pop/dup/swap/over/drop) - Arithmetic (+, -, *, /) - Output (., emit, cr) - Stack inspection (.s, depth)
Example usage: Stack s; stack_init(&s); dict_init(); exec(&s, "10 20 + ."); // Prints "30" exec(&s, "1 2 3 4 .s"); // Shows stack contents
The library is self-contained, requires no dependencies, and handles basic error checking. It was inspired by wanting to understand how Forth works at a fundamental level while keeping the simplicity of C.
I'm curious what other stack-based or concatenative programming enthusiasts think about this approach. Has anyone else built something similar? What features would you add to make it more useful?
8 comments
[ 3.3 ms ] story [ 20.8 ms ] threadAt WHY2025, I gave a talk about the reasons why am working on this. See: https://www.youtube.com/watch?v=akzyyO5wvm0
https://news.ycombinator.com/item?id=45039301
Forth can be beautifully and efficiently implemented in portable c++ using the using continuation passing style via the clang musttail attribute.
Have a look at Tails (not my project):
[1] https://github.com/snej/tails
Starting FORTH https://archive.org/details/LeoBrodieStartingFORTHIntroducti...
Threaded Interpretive Languages https://archive.org/details/R.G.LoeligerThreadedInterpretive...
The latter doesn't even mention FORTH, and describes some very archaic CPU architectures, but I found it fascinating because it builds things from the ground up.
3. I'm not an expert in C but I thought header files shouldn't have code in them. The code should be in a .c file
4. Maybe move the code from USAGE into its own .c file.
I wrote a series of articles that can help in that kind of discovery: http://tumbleforth.hardcoded.net/
To get there, please implement some of the metaprogramming words found in one of the standardized Forths(and if you aren't sure which one, use an earlier spec like Forth83 since the core wordset is smaller, so you run into the "hard stuff" faster).
Forth used in anger towards an application actually tends to resemble Fortran: procedural idioms flinging around lots of named temporary variables. The stack, being just implementation, doesn't give any assistance for everyday programming, unless you extend the system to do so. This is a point on which modern concatenative languages have diverged and tried to add some rigor into it.
I made my own lisp. It used to have a recursive interpreter but I recently finished converting it into a register/stack machine that's essentially a modified version of the Explicit Control Evaluator from Structure and Interpretation of Computer Programs.
https://github.com/lone-lang/lone/blob/master/source/lone/li...
Now I'm thinking about converting it into a CESK machine which I believe is a proper stack machine. Modifying the SICP machine has proven difficult due to the loose stack discipline. I'm told register machines are faster but keeping track of all those ad hoc pushes and pops is turning into a nightmare.
> What features would you add to make it more useful?
The neat part about all these machines is how the stack itself turns into some sort of code. You push some state indicating what you want the machine to do next. Then you set it up so that it evaluates a value. When it's done, that value just flows into whatever the next computation step is.
Making a copy of the stack and wrapping it into a callable that just plugs that value in is how first class continuations are implemented.