Pages 1–2 are a programmer’s guide to Forth as Gforth implements it: the text interpreter, stacks, defining words, control structures, locals, memory, structures, strings, exceptions, compile-time semantics, word lists, files, floating point, debugging and objects. The remaining pages index every word documented in the Gforth Manual by category. Type the filter box to narrow the index; hover a word for its stack effect and description.
Source: Gforth Manual (version 0.7.9, Free Software Foundation) — https://gforth.org/manual/ · guide pages also draw on Leo Brodie, Starting FORTH (FORTH, Inc.). Hover any word for its stack effect, word set and description.| Engine option | Effect |
|---|---|
-i / --image-file f | Load image f instead of gforth.fi |
-p / --path p | Colon-separated search path (overrides GFORTHPATH) |
-m -d -r -f -l | Size of dictionary / data / return / FP / locals stack. Units b e k M G T, e.g. -m 16M |
--die-on-signal | Exit on SIGSEGV etc. instead of turning it into a THROW |
-h -v | Help · version |
--no-rc | Skip ~/.gforthrc |
Startup files $GFORTH_ENV or ~/.gforthrc0 before the command line is processed; ~/.gforthrc after. gforth-itc is the indirect-threaded engine (compatibility).
History is kept in ~/.gforth-history across sessions and is never trimmed — prune it yourself. history-file type prints its name.
Source is a stream of words separated by whitespace — nothing else. There is no grammar, no precedence, no reserved punctuation: +, :, 2dup and my-word! are all just names. Names are case-insensitive.
| Word is… | Interpret state | Compile state |
|---|---|---|
| a defined name | execute it | compile a call to it |
an immediate name | execute it | execute it |
| a number literal | push it | compile it as a literal |
| unrecognised | error: name undefined (-13 throw) | |
: switches to compile state, ; back to interpret. state holds the flag; [ and ] switch it explicitly.
Words such as :, ', s" and char consume text from the input stream at parse time. In stack comments this is written "name" and it is not on the stack.
Gforth keeps four stacks: the data stack (cells, chars, addresses, doubles), the FP stack (floats), the return stack (return addresses and your temporaries), and the locals stack.
| Letter | Means | Letter | Means |
|---|---|---|---|
n | signed integer | r | float (FP stack) |
u | unsigned integer | f | Boolean flag |
w | cell: integer or address | c | character |
d / ud | double-cell signed / unsigned | xt | execution token |
a-addr | cell-aligned address | nt | name token |
c-addr | char-aligned address | wid | word list id |
f-addr | float-aligned address | ior | I/O result (0 = ok) |
i*x j*x | any number of items | "name" | parsed from input, not on stack |
Rule: whatever you >r inside a definition must come back before ; or exit, and must not straddle a loop boundary — counted loops keep their control parameters there too. Use unloop before exiting a loop.
| You type | Interpreter makes |
|---|---|
42 -17 | single-cell integer (in current base) |
3465. 3.465 34.65 | double-cell integer — all three are the same number; the . only marks it as double |
1e 1.e0 +12.E-4 | float — the exponent letter is mandatory |
base for one number)Traps. base @ . always prints 10 — use dec.. Prefer base-execute over hex/decimal so the caller’s base survives. Above base 14, 123E4 is ambiguous (Gforth reads it as an integer) — write 123E+4. Number conversion never checks overflow. The word bin is a file access mode, not a base.
| (none) | signed single | d | signed double |
u | unsigned single | ud du | unsigned double |
c | character | m um | mixed single/double |
2 | two cells (not necessarily a double) | f | floating point |
Forth does no type checking at all, at compile time or run time. -1 u. happily prints 18446744073709551615.
Division. / and /mod have undefined rounding for negative operands. With possibly-negative values use fm/mod (floored, remainder takes the divisor’s sign) or sm/rem (symmetric, remainder takes the dividend’s sign). Nothing is overflow-checked; division by zero may or may not be caught.
A canonical true is a cell with all bits set (−1), false is all bits clear. Any non-zero cell is treated as true by if. Because true is −1, and or xor invert double as logical operators on canonical flags.
0= is also the idiomatic logical NOT for canonical flags; invert is bit-flipping and only agrees with 0= for canonical flags.
A word is visible to later definitions only. Redefining a name does not change earlier callers — they keep calling the old one. That makes it safe to shadow a word, and it is why recursive/recurse exist.
Forth style is many small words, each doing one nameable thing, each tested interactively as you write it. A definition longer than a few lines is a smell. Factor when a phrase repeats, when a definition needs a comment in the middle, or when you cannot describe the word in one line.
rot and -rot to reach an argument, factor differently or use locals.Test in the interpreter as you go: define a word, exercise it with .s, then move on. That interactive edit–test loop is most of Forth’s productivity claim.
create builds the header and reserves data; does> supplies the run-time behaviour that every child will share. At child-execution time the address of the child’s body arrives on the stack.
code1 does> code2 splits into two times: code1 runs when the child is defined, code2 when the child is used. Children are compact — a data field plus a pointer to the shared does> code.
endif is a Gforth synonym for then. These words are compile-time only; they consume a control-flow item (orig/dest) on the control-flow stack, which is why they must nest properly.
of compares the selector against the value; on a match it drops both and runs the clause, otherwise it leaves the selector for the next test. endcase drops the selector at the end — so the default clause sees it on the stack.
| Word | Does |
|---|---|
?of | Takes a flag, not a value — arbitrary tests in a case |
next-case | Ends the case by jumping back to case — turns it into a loop. Does not drop a cell |
contof | Like endof, but restarts the enclosing case instead of leaving it |
Portable implementations of the extensions live in compat/caseext.fs.
DO. It always enters the loop; if the parameters ever become equal you get 264 iterations. Use ?DO at minimum.?DO still runs (wrapping around) when start > limit. +DO / U+DO skip the loop instead — usually what you meant.n +LOOP with negative n; its termination rule is genuinely surprising. Use -DO … -LOOP.>r values pushed outside the loop from inside it, and balance anything you push inside before loop or before touching i.+DO U+DO -DO U-DO -LOOP are Gforth extensions; standard implementations are in compat/loops.fs. Arbitrary control flow can be assembled by hand with CS-PICK / CS-ROLL on the control-flow stack.
Everything after -- inside the braces is a comment. The declaration looks deliberately like a stack comment and usually replaces it. Locals are initialised from the stack, deepest first.
| Value flavour | Address flavour | Type |
|---|---|---|
W: (default) | W^ | cell |
D: | D^ | double |
F: | F^ | float |
C: | C^ | character |
A value-flavoured local produces its value and can be changed with to. A variable-flavoured local (^) produces its address — which becomes invalid the moment its scope ends.
Gforth lets you declare locals anywhere in a colon definition, not just at the start. A local is visible from its declaration to the end of the definition, or to the end of the enclosing control structure if it was declared inside one. scope … endscope restrict visibility explicitly.
Locals are not visible in words you call — pass values on the stack. They cost a little speed, and heavy use of them tends to mean you should factor instead. The standard locals| syntax also exists but the manual recommends against it. Don’t mix brace-locals and brace-free stack comments in the same program — confusing them causes bugs that are hard to see.
A field word turns the address of a record into the address of that field. A type descriptor such as list% leaves ( -- align size ) on the stack.
Extending a structure — start from an existing one instead of struct, and you get an extended record (inheritance of layout):
If a structure contains floats, use foo% %allot constant name rather than create name foo% %allot drop — a created body is guaranteed cell-aligned but not float-aligned. Always write the first-field word even though its offset is zero: the package compiles nothing for it, and the code reads better.
Naming convention: prefix every field with the structure’s name (list-next, not next) — field names are global and generic ones collide.
The modern representation is address + count on the stack, ( c-addr u ). The old counted string keeps its length in the first byte and is passed as a single address.
$ words, gforth)A $-variable holds a pointer to a heap-allocated, length-prefixed buffer that grows as needed.
Unicode: xchar words (xc@+, xchar+, x-width, xemit, xkey) handle multi-byte characters over the same byte buffers.
Digits come out least-significant first, which is why the picture is written in reverse. # divides by base, so the same code prints in any base. Convert single numbers with s>d (signed) or 0 (unsigned) first — and take abs before s>d if you plan to use sign.
catch restores both stack depths to what they were on entry (the contents above that point are undefined), then pushes the throw code. throw unwinds however many call levels it needs to reach the nearest dynamically enclosing catch.
try … restore … endtryThe catch-and-restore idiom (save ['] w catch restore throw) has a window between the catch and the restore where a Ctrl-C loses the cleanup. try/restore/endtry closes it: on an exception the stack depths are restored, the throw code is pushed, and execution resumes right after restore. Related: iferror (exception-only handler), endtry-iferror.
| Code | Meaning | Code | Meaning |
|---|---|---|---|
| −1 | abort | −17 | Pictured output overflow |
| −2 | abort" | −19 | Word name too long |
| −3 | Stack overflow | −22 | Control structure mismatch |
| −4 | Stack underflow | −23 | Address alignment |
| −5 / −6 | Return stack over/underflow | −24 | Invalid numeric argument |
| −8 | Dictionary overflow | −28 | User interrupt (Ctrl-C) |
| −9 | Invalid memory address | −32 | Invalid name argument |
| −10 | Divide by zero | −35 | Invalid block number |
| −13 | Undefined word | −54 | FP underflow |
| −14 | Compile-only word interpreted | −55 | FP unidentified fault |
−4095…−256 are yours via exception; positive codes are free for applications; iors are throwable directly. | |||
Every word has two behaviours: interpretation semantics (what happens when the text interpreter meets it in interpret state) and compilation semantics (what happens in compile state). For an ordinary word the latter is “compile a call”. immediate makes them the same: execute now, even while compiling.
Inside a definition, postpone x arranges that your word, when it runs, does what x would have done at compile time. For an ordinary x that means compiling a call to x; for an immediate x it means executing x. It is the one tool that works for both.
| Token | Get it with | Use it with |
|---|---|---|
| xt execution token | ' name (interpreting), ['] name (compiling), :noname, latestxt, [: ;] | execute, compile,, catch, is, >body |
| nt name token | find-name, latest, >name | name>interpret, name>compile, name>string, id. |
| w xt compilation token | comp' name, [comp'] name | postpone, |
Names live in word lists. Two things are separately settable: the search order (a stack of word lists consulted when a name is looked up, first entry searched first) and the compilation word list (where new definitions go).
delete, list, next) that is already taken.table and cs-wordlist make case-sensitive word lists you can look up at run time.Gforth is case-insensitive by default. table / cs-vocabulary give you case-sensitive lookup without warnings, which is what you want for data rather than code.
Every file word returns an ior: 0 on success, otherwise a code you can throw directly. read-line’s flag is false at end of file — check it, not just the ior.
Gforth keeps floats on a separate stack. A stack comment shows both stacks in one notation, so ( n -- r ) means “takes a cell from the data stack, leaves a float on the FP stack”. Literals need an exponent: 1e, 3.14e0, 1.6e-19.
f=Classic Forth style prefers scaled integers and */ to floats: exact, fast, and enough for most measurement work. Reach for floats when the dynamic range genuinely demands it.
File and line, then the offending word between >>> and <<<, then a return-stack dump read as a backtrace — innermost first, so here bar called foo called @. Names are guesses (return-stack entries are not tagged), so occasional false or missing entries are normal.
The backtrace shown is the one for the first throw after the last catch — put nothrow after a catch that does not rethrow, or you will get a backtrace for the wrong error. Use gforth (not gforth-fast) while developing: it reports stack underflows and division errors the fast engine may miss entirely, and can produce backtraces from primitives.
Three packages ship with Gforth. objects.fs is the recommended one: classes, single inheritance, interfaces, late binding through selectors.
| Word | Role |
|---|---|
class … end-class | Start / finish a class, given its parent |
selector | Declare a late-bound method name (receiver on TOS) |
overrides | Bind an xt to a selector in this class |
field, inst-var,inst-value | Instance data |
heap-new / dict-new | Allocate + construct an object |
construct / init-object | Initialise fields / a raw memory chunk |
m: … ;m, :m | Method definition; binds this |
this, exitm | Receiver · early return from a method |
bind, [bind],[parent], [current] | Early (static) binding to a named class’s method |
interface …end-interface, implementation | Multiple interfaces without multiple inheritance |
protected / public | Hide / expose during class definition |
You may only invoke a selector on an object of the class where it was declared, or a descendant. Immediately before end-class the search order must match what it was after class.
A third model with class…how:…class;, new, init, dispose, super, self, bind, with…endwith, instance pointers (ptr, asptr) and early binding (early). Closer to conventional OO languages; see the manual’s comparison table before choosing.
( x -- y) is fine but (x -- y) is an undefined word (x. Same for ."text" and \comment.." is compile-time only in a strict reading; use .( to print while interpreting.s" buffers are transient. Forth-2012 guarantees only two 80-character buffers — assume a string lives until the next-but-one s". Copy it if it must survive. (Gforth actually allocates, which leaks if you evaluate strings containing s" in a loop.)pad moves. It sits above here, so any allot or new definition relocates it.cells, cell+, chars — never 8 *.u<, not <: addresses above half the address space look negative.base is global state. Change it and every subsequent number in the file reads differently. Use base-execute.defer for a hook you intend to change.>r returns to the wrong place, usually with a spectacular crash far from the cause.^-flavoured local addresses die at the end of scope.DO vs ?DO: equal parameters make DO loop essentially forever.When something goes wrong, the first three things to try are .s, see the word, and drop a ~~ in the middle.
Leo Brodie’s Starting FORTH teaches a FORTH-79 / polyFORTH system. Almost everything transfers, but a few things differ in a modern Standard Forth such as Gforth.
| Book uses | In Gforth |
|---|---|
Screens, LIST, LOAD, the line editor | Text files: require file.fs, your own editor. Blocks still work (use, list, load, thru) if you want them |
NOT | 0= for logical negation, invert for bitwise. NOT is not standard |
ENDIF | THEN (Gforth accepts endif too) |
DO … LOOP | Use ?DO or +DO — see the Loops card |
FORGET word | marker — define a mark, execute it to roll back |
VARIABLE with an initial value (0 VARIABLE X) | variable x takes no value; use 0 value x or variable x 0 x ! |
ASCII c | char c interpreting, [char] c compiling |
<BUILDS … DOES> | create … does> |
." text" while interpreting | .( text) |
-TRAILING, COUNT, <# # #S #>, */, >R R> | Unchanged — these are all still standard |
QUIT, ABORT", PAGE, SPACES, KEY, EXPECT | All present; expect is obsolescent, use accept |
16-bit cells, 2 * for cell size | 64-bit cells — always use cells and cell+ |
Still exactly right in the book: postfix thinking, factoring into tiny words, keeping the stack shallow, the fixed-point/scaling philosophy (*/ and rational approximation instead of floats), pictured numeric output, CREATE…DOES> as the way to extend the compiler, and the habit of testing every word at the terminal as you write it.
A non-destructive stack print (the book’s Handy Hint) is built in here as .s.