#+Starting Forth

This file contains my notes reading the book Starting Forth by Leo Brodie. In
this directory are also several files containing Forth source code. These are my
solutions to the problems found in the book.

* Chapter 1
** Some operations defined in this chapter
  - spaces - ( n -- ) - prints n spaces ('15 spaces' will print 15 spaces to the
    screen).
  - emit - ( c -- ) - prints a number as an ascii character to the screen.
  - : xxx yyy ; - ( -- ) - define new words like this: : star  42 emit ;
  - cr - ( -- ) - print a carriage return to the screen (newline).
  - ." <text> " - ( -- ) - print the string <text> to the screen.
  - . - ( n -- ) - pop a number off the stack and print it.
  - Forth features arithmetic with +, -, / and *.

** The dictionary
   Forth has a "dictionary" where all the word definitions are stored (words =
   functions). When you create a new word with : and ;, the definition is stored
   in the dictionary under the given name.

** The text interpreter
   When a word is entered, Forth will "activate a word called INTERPRET" which
   will look up that word in the dictionary. If it finds a definition, it will
   pass it onto another word called "EXECUTE" which will perform the
   action. Otherwise, it will give it to the numbers-runner called "NUMBER" which
   will push the word onto the stack if it is indeed a number. Otherwise, the
   interpreter will throw an error. It's interesting that all the parts of the
   compilation and interpretation process are described as simple words that are
   part of the Forth system, I wonder if these are redefinable.

** Stack notation
   Stack notation is used to communicate the effects a function has on the stack.
   The basic form is like this: ( before -- after )
   The left side indicates what should be on the stack before you execute a word,
   the right side indicates the things that will be on the stack afterwards.
   The stack notation for +, for example, is ( n1 n2 -- sum ).
   The rightmost item on the left side is the top of the stack (in the previous
   example, this means that n2 is on top of the stack).

** General thoughts
   The end of the chapter features a review of terminology and the words defined
   so far.


* Chapter 2
** General notes
  This chapter is mostly about stack based arithmetic and a few stack
  operations. These are documented tersely and well in the book, so I won't
  write about them here.

  The non-desktructive stack print (.s) is already provided with gforth, but
  that definition looks very inviting. I'm excited for when I can understand it.

  I also find it's a bit difficult to decide on the proper stack layout for a
  function. I guess it will come for practice (or pracicality; when you chain
  multiple words together, I'm guessing there will become a preferred stack
  order).

  I find it weird to use /; I often forget which argument is the dividend and
  which is the divisor. - is more straight forward, weirdly.

** "Problems"
  1. The difference between 'dup dup' and '2dup' is that the former will produce
     two copies of the value on top of the stack, while the latter will produce
     a copy of both the second value of the stack as well as the first.

  2. : 4reverse  swap 2swap swap ;

  3. : 3dup  dup 2over rot ;

  4. I start by factoring the expression like so:
     a² + ab + c = a(a + b) + c
     Then, the answer is trivial.

#+begin_src forth
  ( c a b -- result )
  : answer  over + * + ;
#+end_src

  5.
#+begin_src forth
  ( a b -- result )
  : answer  2dup - rot rot + / ;
#+end_src

  6.
#+begin_src forth
  : homicide  20 + ;
  : arson  10 + ;
  : bookmaking  2 + ;
  : tax-evasion  5 + ;

  : convicted-of 0 ;

  : will-serve  . ." years" ;
#+end_src

  7.
#+begin_src forth
  ( eggs -- )
  : egg.cartons  6 /mod
                 cr . ." carton(s), with " . ." left-over egg(s).";
#+end_src


* Chapter 3
** General notes
   The chapter starts off by talking about how redefining words doesn't actually
   erase the previous definition, but adds a new entry at the "back of the
   dictionary". This means you can use FORGET to remove the newest version of the
   word and get back the old definition. I learned this when I made the forth
   interpreter for Pansy Linux; the dictionary is a reversed linked list with
   this very property.

   The rest of the chapter describes the Forth file system as well as the
   editor. Neither of these are available on modern systems, but it might be fun
   to re-read this chapter for ideas if I ever want to create a virtual machine
   operating system.

** Forget
   As it turns out, gforth doesn't have forget! I'm switching implementation...

   Looks like most implementations don't implement forget. pforth is the only one
   I found so far... I guess I'll use that then?

   NOTE: Forget not only erases the newest version of the word provided, it also
   removes all other words defined after that word.

** The block system
   The book describes how you can interface with files from the Forth
   system. Source files can be stored in "blocks" of 16 lines with 64 characters
   on each line (1024 bytes). To load, say, block 12, you type '12 load' at the
   interpreter.

   This sounds very neat and facilitates Forth as a system in addition to just a
   programming language (and it sounds pretty aesthetic~. I know CollapseOS
   adopted the block model from Forth).

** Style
   There's some style tips here as well:

   1. Separate the name of a word definition from the contents by three spaces.

   2. Break definitions up into phrases, separated by double spaces.

   3. If the definition takes more than one line, indent all but the first line.

   4. Don't put more than one definition on a single line unless the definitions
      are very short and logically related.

** Handy word (just one!)
   depth ( -- n ) - Places the number of items on the stack onto the stack.


* Chapter 4
** General notes
  This chapter is about branching (if/else). It starts with number comparison
  and the basic 'if' form which is like follows:

#+begin_src forth
  if <consequent> then <rest of the program>
#+end_src

  The part after 'then' will always be executed. Special comparison words like =
  will push a true value (which is -1 by the way) on the stack, which will be
  popped off by the conditional check.

  If can also take an else branch:

#+begin_src forth
  if <consequent> else <alternative> then <rest of the program>
#+end_src

  The if form can only be used in a word definition, for some reason. Weird.

  Not reverses the boolean on the stack.

  If's can be nested, but you'll end up having to close off each if with a
  respective then. This leads to weird situations ilke
  if <something> else
  if <something else> else
  ...
  then then then then then ;

  Turns out, any value other than 0 counts as true (like in C).

  This means the logical or operator in Forth is simply +! Ah, but what if the
  values are each other's inverse? If you add -1 and 1 you get 0, which is the
  wrong answer. Because of this, Forth has the or operator which works like
  you'd expect.

** New words
*** Words with built-in if
    ?dup - dup only if the argument is non-zero.
    abort - abort execution and return to the interpreter, clearing the stack in
    the process.
    The book mentions ?stack for checking stack underflows, but it doesn't exist
    in my implementation (fforth). I guess it can be implemented with depth and 0=.
*** Logical operators
    (self explanatory)
    and
    or
*** Comparing numbers
    (these are self explanatory)
**** Two arguments
     =
     <
     >
**** One argument
     0= - this one is actually equivalent to not, but may be used for readability.
     0<
     0>


** "Problems"
  1. Note - My implementation uses -1 as true, instead of 1 as the book.
     1. 1 (not not 1 = -1)
     2. 0 (not not 0 = 0)
     3. 1 (not not 200 = not 0 = -1)

  2. Huh?

  3.
#+begin_src forth
  : card   17 > if ." Alcoholic beverages permitted" else ." Under age" then ;
#+end_src

  4.
#+begin_src forth
  : sign.test   dup 0= if ." ZERO" else
                dup 0< if ." NEGATIVE" else
                         ." POSITIVE" then then drop ;
#+end_src

  5. Simply wrapping the loop in an if statement works!
#+begin_src forth
  : stars  dup if 0 do 42 emit loop then ;
#+end_src

  6. Probably not a good solution, but it works well.
#+begin_src forth
  ( n low-limit hi-limit -- )
  : within rot  ( l h n )
           swap ( l n h )
           over ( l n h n )
           swap ( l n n h )
           <    ( l n t/f )
           rot rot  ( t/f l n )
           <=
           and
  ;

  ( The version provided by the book is much nicer )
  : <rot  rot rot ;
  : within <rot over > not <rot > and ;
  ( But my implementation doesn't have not )
#+end_src

  7.
#+begin_src forth
    : guess  2dup = if ." CORRECT" drop else
             2dup < if ." TOO HIGH" else
                     ." TOO LOW" then then drop ;
#+end_src

  8.
#+begin_src forth
  : n= over = ;

  : speller dup if
                dup 0< if ." NEGATIVE " then
              abs 1 n= if ." ONE" else
                  2 n= if ." TWO" else
                  3 n= if ." THREE" else
                  4 n= if ." FOUR" else
                       ." OUT OF RANGE" then then then then
            else ." ZERO" then drop ;
#+end_src

  9.
#+begin_src forth
  ( TODO )
#+end_src


* Chapter 5
** General notes
   This chapter starts off by introducing a few new arithmetic words and the
   return stack along with a few words for manipulating this. The return stack
   looks really powerful for easing the stack manipulation bit of Forth.

   One thing to note is that the return stack must be empty before the end of a
   word definition.

   The chapter also describes how to deal with floating point numbers in
   Forth. Don't. Instead, use fixed-point numbers but externally represent them
   as floating points. Generally, instead of thinking of expressions like
   (x / y) * z, translate them into (x * z) / y for greater accuracy (which uses
   the */ word in Forth). In general, one can use the expression 3 2 */ to mean
   rational numbers (3/2 in this case) which you can multiply some other
   fixed-point number.
** New words
*** Arithmetic
    These are self explanatory.
    1+
    1-
    2+
    2-
    2*
    2/
*** Miscellaneous math
    abs ( n -- |n| )
    negate ( n -- -n )
    min ( n1 n2 -- n-min )
    max ( n1 n2 -- n-max )
*** Return stack manipulation
    >R ( n -- ) - Pops the first value off the stack and pushes it to the
    parameter stack.
    R> ( -- n ) - The opposite
    I ( -- n ) - Copies the first item off the return stack
    I' ( -- n ) -    --"--  second --"--
    J ( -- n ) -     --"--  third  --"--
*** Scaling operators
    */ ( x y z -- x*y/z ) - This is a word which uses a 32-bit integer as the
    intermediate result of mutliplying x by y. This makes it better to use for
    scaling than simply * and / alone.
    */mod ( x y z -- remainder ) -  The same as /*, but returns the remainder
    rather than the quotient.


* Chapter 6
** General thoughts
   This chapter is all about looping!
** Handy hint
   Typing in an unrecognised word will clear the stack since the interpreter
   will call abort.

   Making quit the last word of a word definition will silence the "ok."
** Looping constructs
*** Definite loops -- do...loop
    This is your basic for loop in other languages. The syntax is the following:
    limit index do ... loop
    So you put the limit first, then the starting index, then do, the body and
    finally loop.
    The do loop works by first pushing the limit and the index onto the return
    stack and incrementing the index until it is the same as the limit. This
    means you can use the i word to get a copy of the index at any given moment
    in the loop!
    Since we can nest loops, the words i and j make a bit more sense. You can
    use j to access the index of the outer loop and i to access the index of the
    inner one.

    for (int j = 0; j < 10; j++)
        for (int i = 0; i < 10; i++)
            ...

    Looks familiar?

    +loop can make the index go up by a specific increment. It pops a value off
    the stack and increments the index by that number.

    Do loops terminate when (going up) the index reaches or passes the limit and
    (when going down) it passes the limit. A do loop always executes at least
    once.

    One can use the word leave to set the limit to equal the index, so that the
    loop will immediately terminate on the next time loop is executed. This can
    be useful for early exits.
*** Indefinite loops
    Indefinite loops are like a do while loop, they loop if a condition is true
    by the end of the body execution.

    The basic indefinite loop is on the form:

    begin xxx f until

    Where xxx is the body of the loop and f is the boolean flag indicating if
    the loop should, well, loop.

    A simple infinite loop can then be defined like so:

    begin xxx 0 until

    There's another form of the loop as well, with syntax like this:

    begin xxx f while yyy repeat

    This one's weird. It performs xxx, then checks for a boolean true. If it's
    true, it performs yyy and repeats again. The begin...until loop will loop on
    the opposite condition. That is, it will only loop if the condition is
    false.


* Chapter 7
** General notes
   This chapter is about number representations, like unsigned, double width,
   hexadecimal etc.

   Turns out that the and and or words defined earlier are actually bitwise
   operators. They work fine as logical and/or regardless.
** Double length numbers
   To push a double length number onto the stack, use punctuation in the number.
   Punctuation works with , and . and a few other characters.
   So 4.000.000.000.000.000.000.000 pushes that number as two cells.
** Number formatting
   One can create number formatting words with the special words <# and #>. The
   book has good sections on this, I won't bother trying to word them myself
   here. NOTE! These only work on unsigned, double length words. To make them
   work on single length words, put a 0 on the stack before calling it.

   This is a sort of DSL, kinda like format in Common Lisp. I wonder if there
   are more of these in Forth, and how easy it is to make one...
** New words
*** Unsigned number manipulation
    The numbers on the stack are both unsigned and signed at the same time. The
    programmer decides what representation they are by the operations performed
    on them. Most arithmetic operations have an unsigned equivalent:
    u. ( u -- ) Prints the unsigned number u.
    u*, u/mod, u< does what you'd expect.
    do ... /loop is your normal loop, but with unsigned index, limit and
    increment. It takes an increment value, like +loop.
*** Changing the base
    One can change the base of the program with the words hex (hexadecimal),
    octal and decimal.
    You can also change the base to whatever you please with 'n base !'. That
    means you can declare : binary  2 base ! ; and see numbers in binary form!
    That's pretty cool.
*** Double length numbers
    d. ( d -- ) - Prints a signed, double length number.
    d+, d-, dnegate, dabs, dmax, dmin, d=, d0=, d<, du< do what you'd expect.
    d.r ( d width -- ) - Print the signed 32 bit number, right justified within
    the field width.


* Chapter 8
** General notes
   This chapter is called "Variables, constants and arrays". My normie
   programming brain thinks these are good things, and will hopefully make the
   code a bit more readable?
** Variables
   You declare a variable like so:

   variable <var>

   One can set the variable like so:

   <value> <var> !

   This means that the earlier base changing trick (<num> base !) is actually
   just changing a global "base" variable!

   ! is pronounced "store".

   @ is the opposite of !, and is used for getting the values stored in a
   variable. It's pronounced "fetch" and works thusly:

   <variable> @

   Printing the value of a variable (<var> @ .) is so common that Forth has a
   separate word for it, ?.

   Since variables are accessed at run time, it's good to store often changed
   values there instead of in words since words that use those words would have
   to be recompiled to work with the new definition. Variable declaration is
   similar to word declaration, but it compiles a new word which when called
   pushes its value address onto the stack. That's how <value> <var> ! works, it
   pushes a value, pushes an address, and stores that value into that address.
** Constants
   Constants are declared like this:

   <value> constant <name>

   The value can be retrieved by executing the constant name.
** Arrays
   Arrays are simply variables with extra memory. What does that mean? To make
   an array called "arr", you do this:

   variable arr  8 allot

   The "8 allot" part means that we want arr to contain 8 additional bytes, that
   is, 1 extra cell on modern machines.

   The new fields can be accessed with simple pointer arithmetic.

   2 arr 8 + ! - Sets the second element of the array to 2 (on a 64-bit machine).

   You can make an array with initial elements using create.

   create xs 1 , 2 , 3 ,

   will create an array called xs with 1, 2 and 3 as its initial elements. They
   are each a cell big. Create creates an array which can be manipulated as
   normal (the book has a notice for polyFORTH, but I don't think it's
   relevant).
** Byte arrays
   In addition to arrays, Forth also has byte arrays which operate on bytes
   instead of cells. I think this one's probably better for portability since
   you don't have to consider the cell size on different systems when using
   it. You also don't have to double the index of an array since each value
   correspond to a single byte.

   Byte arrays can also be created with initial values, like you can for normal
   arrays with create. The difference is that you use c, instead of ,.

   create bytes 1 c, 2 c, 3 c,
** New words
   !, @ and ? are described in the variables section.
   +! ( n adr -- ) - Increments the value at adr with n.
   Constant and variable operations can be prefixed with a 2 to mean a
   double-length variable/constant.
   fill ( adr n b -- ) - Fill n bytes of memory beginning at the address with
   value b.
   erase ( adr n -- ) - Like '<adr> <n> 0 fill'
   c! and c@ are like ! and @ but for byte values.


* Chapter 9
** General notes
   This looks to be a very interesting chapter. It's all about how Forth works
   internally, which is extremely captivating.

   In the section "vectored execution" the book goes over a powerful
   strategy. Since the ' word gives the address of a word, you can store it in a
   variable. Then, later, you can execute this word with <var> @ execute. This
   means you can have a word have different meanings in different parts of the
   program! This makes it possible to compile words and place them into
   variables, which bypasses the need for recompiling every word that uses that
   word.
** Dictionary entries
   Dictionary entries are described in the book. They have the following
   structure:

   Name
   Link (to previous word, the dictionary is a backwards linked list)
   Code pointer
   Parameter field

   The code pointer is what makes variables, constants and colon definitions
   different. Variables have a code pointer pointing to code which pushes the
   variable's address onto the stack, and constants have a similar one but
   pushes a value rather than an address. For other words, it points to machine
   code to be executed when the word is invoked.

   The parameter field contains data, and the size of it depends on the type of
   variable, constant or colond definition. Normal variables/constants have a 1
   cell sized parameter field, 2constant/2variable declares a constant/variable
   with a 2 cell sized parameter field and colon definitions can have
   arbitrarily long parameter fields. The address provided by tick and used by
   execute is the parameter field address (pfa).

   The name and the link is called the 'header' and the code pointer and the
   parameter field is called the 'body'.

   In colon defined words, the parameter field contaiins the addresses of the
   words that comprise the defintion. These addresses are called code field
   addresses.
** How colon defined words work
   At the end of any colon defined word sits a call to exit. When executing a
   word, the interpreter will first push the current interpreter pointer to the
   return stack. Exit will pop this address and return to it. Therefore, you can
   change where a colon defined word will return to by manipulating the return
   stack directly! This also means that you can use exit as an 'early return' to
   a word.
** The pad
   The pad is some memory location a fixed place after here which is used for
   text processing. Since it starts a fixed point after here, it moves as
   definitions are added.
** The parameter stack
   The parameter stack (remember, this is the thing referred to as just "the
   stack") resides far above the pad in memory. The stack is in reality just
   memory with a pointer that changes as we push and pop items off it. The stack
   grows downwards, that is it begins at high memory and grows towards low
   memory. The stack pointer memory value can be fetched with 's. The current
   top value of the stack is therefore the same as 's @ (which is the same as
   dup!). The point right before the bottom of the stack is pointed to by s0
   (which doesn't seem to be defined in gforth!). 's, s0 and h are not required
   by the standard, which explains why they're not available in gforth.
** Input buffer
   The text retrieved from the command line interface is stored in the input
   message buffer, which is located just above the stack and grows upwards.
** Return stack
   Above the input buffer is the return stack. It works the same as the
   parameter stack, but doesn't have words like 's and s0 defined for it.
** User variables
   Variables available to the user (like base) is stored above the return
   stack. User variables are different from the ones defined by the user (with
   variable). They're kept in an array called the "user table". This was
   probably more relevant back in the day with multi-user systems, but each user
   has their own user table, meaning that if one person changes a base, it won't
   affect others.
** Vocabularies
   Vocabularies work as namespaces for word definitions. The book describes
   three vocabularies, the standard Forth vocabulary, editor (not present on
   modern systems) and assembly (which allows for making words in the computers
   assembly language??). Now I want to know how to use this assembly
   vocabulary. Vocabularies are just a part of the dictionary, but words of
   particular vocabularies only point to words of the same vocabulary in the
   dictionary. The current vocabulary is called the 'context' (it can be
   accessed with the word context, but it's just an address). The current
   vocabulary new words are linked to is found in the variable current. To
   change current, use the word definitions (which will take the current context
   and put it in current).
** New words
   ' ( -- adr ) - Takes the next word of the input stream and pushes the address onto the
   stack. Since ' takes the *next word in the input stream* you can do stuff
   like

   : set  ' <var> ! ;

   And invoke it like "set <word>". The input stream is visible, even to words.

   dump ( adr n -- ) - Prints the first n bytes of data found at adr.

   ['] - Takes the next word inside the definition and puts the address on the
   stack. It ignores the input stream, which will be handy.

   h ( -- adr ) - Returns the current address in the dictionary. This increases
   as more words are defined.

   here ( -- n ) - The same as h @. You can use this to see how much memory
   something takes by first performing here, defining something and comparing
   the new value of here to the one on the stack.

   , is explained to be the same as 'here ! 2 allot'

   user - define a new user variable.


* Chapter 10
** General notes
   Ah, a practical chapter (it's about i/o).

   It starts off with some (now) irrelevant information about blocks.

   It's a difficult chapter to read, since half the information is in this way
   irrelevant.
** "New" words (some old)
*** Output
    emit ( c -- ) - Prints a value on the stack as an ascii character (using the
    lower byte).

    type ( adr n -- ) - Prints n bytes starting at adr. Used for printing
    strings.
*** Input
    key ( -- c ) - Waits for a key to be pressed, then pushes that ascii value
    onto the stack. NOTE: This works pretty bad in emacs since it doesn't
    support terminal codes that well.

    expect ( adr u -- ) - Reads u bytes as a string and stores it at adr.

    word ( c -- adr ) - Read a word from the input, using c as a delimiter. The
    address returned has the count as the first value and the string follows.

    text ( c -- ) - Reads a string using c as a delimiter, but places the string
    in the pad. Text is non-standard and doesn't exist in gforth.

    query ( -- ) - Expect, but read 80 chars and store them in the input message
    buffer. The input has to be valid character.
*** Memory manipulation
    move ( adr1 adr2 u -- ) - Copies u cells from adr1 to adr2.

    cmove ( adr1 adr2 u -- ) - Like move, but for bytes instead of cells.
*** String operations
    count ( adr -- adr+1 u ) - Takes the address of a string and returns the
    length of the string (u) as well as the incremented address.

    -text ( adr1 u adr2 -- f ) - Compares two strings of length u (adr1 and
    adr2).


* Chapter 11
** General notes
   What is this chapter about? Metaprogramming? The chapter name is "extending
   the compiler" which makes my Lisp brain tingle.
** Compile time and run time
   One of the first things the chapter tackles is the difference between run
   time and compile time. You see, some words have both run time behaviour and
   compile time behaviour. These types of words fall in one of two categories;
   defining words and compiling words.

   Constant is a defining word, as it takes an identifier at compile time and
   exhibits run time behaviour in that, every time you call that word, you get
   a value on the stack.

   A compiling word is a word used inside a colon definition which does
   different stuff when the word is defined from what is shown at run time. For
   example, ." will at compile time embed the string into the word's parameter
   field, but at run time print the string. Other examples include if and loop.

   The first example of metaprogramming uses create and does>. I'm not really
   seeing the power yet, and it still looks a bit limiting.

   The next section covers how to change the behaviour of the colon
   compiler. Now we're talking! Any word can be made immediate (word that will
   be executed at definition time) by simply placing the immediate word behind a
   definition.

   : say-hello   ." Hello " ; immediaten

   Now, if this word is placed in a colon definition, it will execute at compile
   time rather than run time. It can still be executed interactively.
** New words
   does> ( -- pfa ) - Marks the end of the compile time behaviour in a definition and
   the start of the run time behaviour it will exhibit. It pushes the pfa of the
   word defined onto the stack.

   compile ( -- ) - Used in immediate definitions. Places the following words
   address inside the definition, making it possible to describe run time
   behaviour. Not available in gforth.

   [compile] ( -- ) - Used in definitions to move the compile time behaviour of
   an immediate word to run time.

   literal Compile time ( n -- ) Run time ( -- n ) - Compiles a literal value on
   the stack by embedding the run time code for pushing the value onto the stack
   and the value itself inside a definition.

   [ ( -- ) - Stop compilation and start executing words.

   ] ( -- ) - Start compilation mode again. These words can be used in
   conjuction with literal to do i.e. arithmetic at compile time.
