# Snobol4th

A toy Forth written in Snobol4.

This Forth is implemented as a "pure" interpreter, which simply
means it has no compiling or translation step before immediately
executing the source code as string data.  In other words, it
reads the program pretty much exactly like a human would.

Only enough of the Forth language was implemented to be able to
execute a "99 Bottles of Beer" lyric-printing program.

[I learned Snobol and then wrote a toy Forth](https://ratfactor.com/snobol/)

Snobol4 is an unusual language of contrasts. String
pattern-matching operations are first-class items in the language
and can be combined and composed into expressive string parsing
and tokenization. Yet general program control flow is essentially
a bunch of labeled GOTOs and branching is based on a hidden layer
of "success" and "fail" results of any operation.

[Ratfactor's Judgement of Snobol4](https://ratfactor.com/snobol/judgement)

I highly recommend having a small, specific goal when implementing
any project as open-ended as a programming language. A lot of my
real-world programming often comes down to relatively simple
string manipulation, so the 99 bottles program has long been a
favorite. It also exercises basic repetition and if/else logic.

[99-bottles-of-beer-.net](https://www.99-bottles-of-beer.net/)

[Have a target for your programming language](https://ratfactor.com/cards/toy-language-target)


## The files

**forth.sno** - The actual program, a minimal Forth implemented
in Snobol4.

**99.forth** - A Forth entry for the 99 bottles...

**99output.txt** - Your very own souvenir copy of the successful run of 99.forth!

**test.forth** - The test Forth I _actually_ ran as I built up the word dictionary needed to execute 99.forth.

**README.md** - That's me!

**log.txt** - Abandoned dev log of dubious worth!

## Running it

You can interact directly with the interpreter like so:

    $ snobol forth.sno
    ." Hello world!" CR
    Hello world!
    ^D

Run a Forth script by piping it to the interpreter:

    $ snobol forth.sno < 99.forth
    99 bottles of beer on the wall
    99 bottles of beer
    Take one down and pass it around.
    98 bottles of beer on the wall
    ...

## A bit more about this implementation

I chose to play to Snobol's strengths by storing and executing
even "compiled" words in string form rather than machine code or
bytecode for a VM.

Because of the GOTO-like behavior of control flow, writing a Forth
in Snobol is both very different and very similar to writing one
in assembly language.

It feels like cheating and a bit un-Forthy, but while matching and
executing source code directly makes a lot of things easier (and
simpler!), it also means you're going well off the beaten path in
terms of how various words are implemented. Some words don't even
make much sense when you're not actually converting the source
into bytecode or working with raw memory.

However, jumping around in strings can actually be quite similar
to jumping around in binary code in memory. Again, it's very
similar to how you might "execute" the code yourself if you were
doing it on paper.
