Chris Collins

Lab · Playground

Forth playground

A small Forth that runs in your browser — the data stack, defining new words, loops, and memory, in the language that fits in 8 KB.

Code blocks on this page are editable — change them and press Run.

Forth is the language Chuck Moore built in the late 1960s to control radio telescopes, and it still turns up wherever memory is tiny: boot firmware (Open Firmware on old Macs and Suns), spacecraft, and hobby microcontrollers. There is almost no syntax. A program is a stream of words separated by spaces; numbers go onto a stack, and every word takes its arguments from the stack and leaves its results there. You grow the language by defining new words, until the problem reads like its own little vocabulary.

These blocks run a small ANS-style Forth written for this site — it is part of the playground script, so there is nothing to download. Each run starts a fresh system, and whatever is left on the stack at the end is shown after it, like <2> 30 20 ok (the depth, then the items, top last). Comments are ( like this ) or \ to the end of the line; the stack comments such as ( a b — sum ) are the Forth convention for "takes a and b, leaves sum".

The stack: push numbers, then let words consume them
2 3 + .          \ 5   — "." pops the top of the stack and prints it
2 3 4 * + .      \ 14  — no precedence rules: it is just the order words run in
cr
10 20 30 .s      \ show the stack without changing it
cr
swap .s cr       \ exchange the top two
rot .s cr        \ bring the third item to the top
over .s cr       \ copy the second item over the top
drop drop        \ leave two items: you will see them after "ok"
Define words, and the language grows
: square ( n -- n*n )  dup * ;
: cube   ( n -- n^3 )  dup square * ;
: hyp2   ( a b -- a²+b² )  square swap square + ;

7 square . cr
3 cube . cr
3 4 hyp2 . cr

\ Fixed-point maths, Forth style: */ multiplies then divides with no overflow in between
: c>f ( celsius -- fahrenheit )  9 5 */ 32 + ;
-40 c>f .  0 c>f .  37 c>f .  100 c>f . cr
Loops: DO … LOOP counts, I is the index
: row ( n -- )  11 1 do  dup i * 4 .r  loop  drop ;
: table ( -- )  11 1 do  i row cr  loop ;
table
Decisions: IF … ELSE … THEN, and FizzBuzz
: fizz?  ( n -- flag )  3 mod 0= ;
: buzz?  ( n -- flag )  5 mod 0= ;
: fizzbuzz ( n -- )
  dup fizz? over buzz? and if drop ." FizzBuzz" else
  dup fizz?               if drop ." Fizz"     else
  dup buzz?               if drop ." Buzz"     else
  .  then then then ;
: run  21 1 do  i fizzbuzz space  loop ;
run
Recursion and BEGIN … WHILE … REPEAT
\ Euclid's greatest common divisor, as a loop
: gcd ( a b -- g )  begin dup while  tuck mod  repeat drop ;
1071 462 gcd . cr

\ The same idea recursively: RECURSE calls the word being defined
: gcd-r ( a b -- g )  ?dup if  tuck mod recurse  then ;
1071 462 gcd-r . cr

\ Collatz: how many steps from n down to 1?
: step ( n -- n' )  dup 2 mod if  3 * 1+  else  2/  then ;
: collatz ( n -- steps )  0 swap  begin dup 1 > while  step swap 1+ swap  repeat drop ;
27 collatz . cr
Variables, constants, and memory you lay out yourself
variable total
0 total !                      \ !  stores:  value address !
5 total +!  12 total +!        \ +! adds into memory
total @ . cr                   \ @  fetches: 17

8 constant #samples
create samples  3 , 9 , 4 , 1 , 7 , 2 , 8 , 6 ,   \ , compiles a cell into memory

: sample ( i -- n )  cells samples + @ ;
: sum  ( -- n )  0  #samples 0 do  i sample +  loop ;
: biggest ( -- n )  0 sample  #samples 1 do  i sample max  loop ;
." sum " sum .  ." max " biggest . cr

255 dup hex .  decimal . cr     \ BASE changes how numbers print (and parse): FF 255
Execution tokens: words as values
\ ' (tick) gives a word's execution token; EXECUTE runs it — Forth's function pointers
: twice ( xt n -- n' )  over execute swap execute ;
: double  2* ;
: inc     1+ ;
' double 5 twice . cr      \ 20
' inc    5 twice . cr      \ 7
variable op  ' double op !   \ keep an xt in a variable…
9 op @ execute . cr        \ …and call through it: 18

Things to try: define : cube-root by searching with a loop, change table to print squares only, or type words to list every word the system knows.