/ff

A Simple Forth System for Linux on i386 and ARM CPUs

Primary LanguageForth

ff - A Simple FORTH System
==========================



Introduction
------------

This is `ff`, an implementation of the Forth programming language for 32-bit 
CPUs on Linux and Plan 9. `ff` is indirect-threaded and currently available for 
x86 and ARM processors. It is kept intentionally simple to reduce size and 
complexity to a minimum. Floating-point math and double-precision numbers are 
not supported and only very limited I/O facilities are provided. On the other 
hand, the machine-code portion is small and it should be very easy to port `ff` 
to other architectures. 

Installation
------------

`ff` is available in pre-compiled, binary form and requires no additional 
libraries, so it is not necessary to build it to get going. 

The following files are included in the distribution:

    ff-i386         x86 executable
    ff-arm          ARM executable
    ff-i386-plan9   x86 executable for Plan 9
    README          This file
    ff-i386.s       Assembler sources for x86 (NASM syntax)
    ff-arm.s        Assembler sources for ARM (GAS syntax)
    primitives.s    Primitive dictionary
    words-nasm.s    Bootstrapping core dictionary (NASM syntax)
    words-gas.s     Bootstrapping core dictionary (GAS syntax)
    core.f          Core dictionary sources
    meta.f          Meta-compiler sources
    meta-install.f  Meta-compiler installation
    elf.f           Meta-compiler (elf binary generation)
    cross.f         Meta-compiler (Plan 9 a.out binary generation)
    stuff.f         Miscellaneous words
    blocks.f        Block- and buffer words
    ed.f            Block-editor sources
    robots.f        A simple game
    forth           Tcl/Tk frontend
    x-i386.f        Settings for cross-compilation to x86
    x-arm.f         Settings for cross-compilation to ARM
    x-i386-plan9.f  Settings for cross-compilation to x86 on Plan 9

In case you want to build `ff-*` yourself you will need an assembler - 
[NASM][1] for the x86 version and [GNU as][2] for ARM, the latter being usually 
available on an ARM-based linux with development tools installed. ARM `ff` can 
also easily be cross-assembled from a non-ARM Linux system. 

The necessary build-commands look like this:

    nasm -f elf ff-i386.s -o ff-i386.o
    ld ff-i386.o -o ff-i386               # add "-m elf_i386" on an x86_64 system

Or, for an ARM based system:

    as ff-arm.s -o ff-arm.o
    ld ff-arm.o -o ff-arm

Note that this creates only a minimal Forth system, sufficient to run the 
metacompiler. To generate or re-generate a complete binary, start the initial 
executable and enter: 

    include meta.f
    include elf.f
    include meta-install.f
    include core.f
    <ARCH> msave ff
    bye

where `<ARCH>` should be either `i386` or `arm`, depending on the system this 
is running on.

On Plan 9, re-compilation is slightly different:

    include meta.f
    include a.out.f
    include meta-install.f
    include core.f
    msave ff
    bye

The C library (`libc`) is not used, `ff` directly invokes Linux or Plan 9 
system-calls. 

Cross-compilation is similar, but needs an additional file with hard-coded
addresses, together with binaries containing the target-specific machine code
of the kernel in the `boot` directory. So, assuming `ff-arm` is available as 
`boot/ff-arm`:

    include meta.f
    0 target-endianness      \ if target and host have different byte-order
                             \ 0 = big, 1 = little
    include elf.f
    include x-arm.f          \ or "include x-i386.f"
    include meta-install.f
    include core.f
    arm msave ff             \ or "i386 msave ff"
    bye

Again, replace `elf.f` with `a.out.f` and drop the argument to `msave` on
Plan 9. Note that ARM/Plan 9 is currently not supported.

Porting to other platforms should be straightforward, since the assembler 
portion is quite small. Porting the system to embedded systems should also 
don't present any problems - just add or remove primitive words in `ff-*.s` as 
necessary and metacompile. 

Some additional files and scripts for building and cross-compilation are
avaialble in the [`ff` development repository][5]. 


Usage
-----

`ff` reads Forth commands from stdin, interpreting words as they are parsed. A 
subset of the [Forth ANSI standard][3] is supported, see below for a 
description of all words that are available. 

All input is parsed case-sensitively, and the base dictionary contains 
lowercase words. 

If one or more command-line arguments are given, then the first argument is 
loaded as an image-file (using `bload`.) 

The `forth` script implements a simple text-based front-end for `ff`, and is 
written in Tcl/Tk. It provides a very basic *terminal* and implements basic 
text-editing functionality. It defaults to invoking a binary named `ff` which 
should be in the `PATH` (if it isn't copy or symlink the `ff-*` binary for your 
architecture) 

Command-line options that the `forth` script accepts:

    -background COLORNAME          select background color
    -foreground COLORNAME          select foreground color
    -fontname FONTNAME             select font
    -fontsize FONTSIZE             select fontsize
    -execute FILENAME              load Tcl source from FILENAME at startup
    -ff FILENAME                   run FILENAME instead of the default "ff"
    -cd DIRECTORY                  change working directory to DIRECTORY
    -init STRING                   Forth code to be executed on startup
    -image FILENAME                Load image-file on startup (uses "-init")

Output from `ff` is appended to any text in the window. The character `^L` 
(ASCII 12) is handled specially and clears the window.  

`RETURN` will send the current selection to the Forth interpreter, or the 
current line if no text is currently selected. Pressing the `Insert` key will 
enter *hold* mode, which means `RETURN` will just insert a newline, without 
executing any code. Pressing `Insert` again will send all text beginning from 
the location where `Insert` was first pressed up to the current cursor position 
and disable hold mode. 

Pressing the right mouse button on a word in the window will execute the Forth 
statement `command <word>`. `command` is a deferred word defined in `stuff.f` 
that can be used to implement a poor man's menu system by just right-clicking 
words in the window. 

Pressing `Escape` terminates the Forth interpreter, pressing it again exits
the front-end.

The function keys can be bound to text that is either inserted at the current
position, or (if it ends with a newline) immediately executed. To bind a key to
a particular sequence, select the text you want to bind and press `Control-F<n>`,
where `F<n>` is the function key you want to change.

`Control-Up` and `Control-Down` move the currently shown screen, when the
block and editor extensions are loaded.

If a file called `.forth` exists in the `HOME` directory, it is loaded before 
startup and can be used to customize the front-end. Study the source code for 
`forth` to learn more about it. 

If the Forth system crashes, the background color turns to black and a message 
is printed. Press `RETURN` to restart. 


Unicode support
---------------

Partial UTF-8 support is provided: `emit`, `char` and `[char]` encode and 
decode UTF-8 sequences correctly. `key` does not. The front-end allows entering 
unicode code-points using the `Delete` key, which accepts either a hexadecimal 
code-point or a named character. The latter can be defined in your `~/.forth` 
file by adding a definition for the `snippets` variable, holding lists of 
2-element lists: 

    set snippets {
      {alpha "\u03b1"}
      ...
    }


Builtin words
-------------

- Standard words (ANS)

  Defined in the core system:

  `!` `#` `#>` `<#` `#s` `'` `(` `*` `+` `+!` `+loop` `,` `-` `.` `."` `.r` `/` 
  `/mod` `0<` `0<>` `0=` `0>` `1+` `1-` `2*` `2/` `2drop` `2dup` `:` `;` `<` `<#` 
  `<>` `=` `>` `>body` `>in` `>r` `?do` `?dup` `@` `[` `[']` `[char]` `\` `]` 
  `abort` `abort"` `abs` `accept` `again` `align` `aligned` `allot` `and` `base` 
  `begin` `bl` `blk` `c!` `c,` `c@` `cell+` `cells` `char` `clear` `close-file` 
  `cmove` `cmove>` `compare` `constant` `count` `cr` `create` `decimal` `defer` 
  `depth` `do` `drop` `dup` `else` `emit` `erase` `execute` `exit` `false` `fill` 
  `find` `h` `here` `hex` `hold` `i` `if` `immediate` `include` `included` 
  `invert` `is` `j` `key` `list` `literal` `load` `loop` `lshift` `max` `min` 
  `mod` `negate` `nip` `off` `on` `open-file` `or` `over` `pad` `page` `pick` 
  `quit` `r/o` `r/w` `r>` `r@` `read-file` `recurse` `refill` `repeat` 
  `reposition-file` `reset` `restore-input` `rot` `rshift` `s"` `save-input` 
  `scr` `search` `sign` `sliteral` `space` `spaces` `state` `string` `swap` 
  `then` `tib` `true` `tuck` `type` `u.` `u.r` `unloop` `until` `unused` 
  `variable` `w/o` `while` `within` `word` `write-file` `xor` `does>` `current` 

  Defined in the source files `stuff.f` and `blocks.f`:
  
  `2@` `2!` `2>r` `2r>` `?` `-trailing` `.s` `:noname` `/string` `also` `block` 
  `buffer` `buffer:` `case` `context` `current` `definitions` `dump` 
  `empty-buffers` `endcase` `endof` `forget` `forth` `list` `load` `marker` `of` 
  `only` `order` `postpone` `previous` `scr` `thru` `update` `vocabulary` `words` 

- Notes:

  - `while` is only allowed once inside a `begin`/`repeat` construct.

  - `<#`, `#`, `#s` and `#>` only handle single-precision numbers.

  - There are no "state-smart" words. `is`, `."` and `s"` are intended
    to be used inside colon definitions.

- Non-standard core words

    `2nip           ( x y -- y )`

    Drops the 2nd item on the stack.

    `<builds        ( | <word> -- )`

    Compile-time part of `<builds ... does>` pair. In other Forth systems
    `create` is normally used for this.

    `>limit         ( -- a )`

    Variable holding the end-index in the text-input-buffer (TIB).

    `?stack         ( -- )`

    Aborts on stack-underflow.

    `(.)            ( n1 -- a n2 )`

    Convert signed number to string and return address and length.

    `_start         ( -- a )`

    Pushes address of machine-code entry-point.

    `_end           ( -- a )`

    Pushes end-address of machine-code section.

    `args           ( ... -- )`

    Pushes a pointer to an array of cells, holding the number of
    command line arguments, followed by pointers to zero-terminated
    strings, one for each command-line argument (including the program
    name), terminated by 0.

    `boot           ( ... -- )`

    Completely reinitializes the system and invokes `cold`.

    `bload          ( a n -- )`

    Loads a memory-image from `<filename>` restoring the state at
    which the image was last saved with `save-image`. Note that
    image-files are not portable and depend on the executable being
    exactly the same at both save- and load-time. After loading the
    image, the deferred word `startup` is invoked.

    `bye            ( -- )`

    Terminates `ff`.

    `c"             ( | ..." -- a )`

    Stores a counted string in the dictionary and pushes its
    address. To be used in interpreted mode.

    `cas            ( a1 x y -- f )`

    Perform an atomic _compare and swap_ operation on address `a1`,
    i.e.  compares the contents of the given address with `x` and, if
    it is equal, replaces the stored value with `y`,
    atomically. Pushes a flag indicating whether the operation
    succeeded.

    `cold           ( ... -- )`

    Performs a "cold" start, completely re-initializing the system.

    `crash          ( ... -- )`

    Called when an uninitialized deferred word is invoked.
 
    `halt           ( n -- )`

    Terminate with exit-code `n`.

    `heaptop        ( -- a )`

    Variable holding the address of the top of the available heap.

    `interpret      ( | ... -- )`

    Interprets words from the text-input-buffer (TIB).

    `load-image     ( | <filename> -- )`

    Invokes `bload` with the given filename.

    `mmap           ( a1 -- a2 )`

    Invokes the Linux `mmap` system call. `a1` should be the address
    of an `mmap_arg_struct` holding the parameters. See [this page][4]
    for more details. This word is a no-op on Plan 9.

    `number         ( a n1 -- n2 -1 | a n1 0 )`

    Parses number given by string and either pushes the parsed
    number and `true` or keeps the argument items, pushing `false`,
    if the number is not a valid integer.

    `parse          ( c | ... -- a )`

    Reads the next characters in the input-stream until character
    `c` is encountered and returns the address of a counted
    string. Note that this word is not ANSI compatible (it returns a
    counted string.)

    `prompt         ( -- )`

    A deferred word that prints the prompt that is shown when the
    interpreter waits for input. The default prints ` ok` and advances
    to a new line.

    `query          ( -- )`

    Reads a new line from stdin into the TIB.

    `reveal         ( -- )`

    Exposes the most recent item in the dictionary (see also
    `smudge`.)

    `rshifta        ( n1 n2 -- n3 )`

    Performs an arithmetic shift of `n1` by `n2` bits.

    `s0             ( -- a )`

    Variable holding the initial stack-pointer.

    `s@             ( -- a )`

    Pushes the current stack-pointer.

    `save-image     ( | <filename> -- )`

    Saves the current dictionary to `<filename>`.

    `signum         ( n1 -- n2 )`

    Pushes -1, 0 or 1, depending on whether `n1` is negative, zero
    or positive.

    `smudge         ( -- )`

    Hides the most recent dictionary entry.

    `startup        ( -- )`

    Invoked after a binary image is loaded. The default behaviour is to print
    `"ok "` and invoke `abort`.

    `u/mod          ( u1 u2 -- u3 u4 )`

    Like `/mod`, but treats arguments as unsigned numbers.

    `utfdecode      ( a1 -- a2 c )`

    Decodes the UTF-8 byte sequence at address `a1` and returns the address
    directly after the byte sequence and the unicode code-point.

    `utfencode      ( a c -- a n )`

    Encodes the unicode code-point `c` as an UTF-8 byte sequence at address
    `a`, and returns the target address and the number of bytes.

- Optional words

  Some additional words are available in the source files
  `stuff.f`. Read that file to learn more about what's included.
  

The Block-file Editor
---------------------

The system includes an optional simple command-based block-editor in
the file `ed.f`.  See below for a list of available editor
commands. Blocks are stored in a file called `blockfile`, which must
reside in the current working directory. Note that the editor needs
the words in `blocks.f`.

To create a blockfile, use the following commands

    # creates a blank file of 1024 blocks:
    dd if=/dev/zero bs=1024 count=1024 | tr '\000' ' ' >blockfile

The editor maintains two buffers, together with the current edited
block (`scr`): the *insertion-buffer* and the *find-buffer*. The
former is used in commands that add or insert text, the latter holds
text that is searched.

The editor is provided in source form in the file `ed.f`. The
ANS block- and buffer-related words can be found in `blocks.f`.

All editor words exist in the `editor` vocabulary, so execute `editor`
before using them.

- Editor commands:

    `b              ( -- )`

    List previous screen.

    `copy           ( n1 n2 -- )`

    Copies contents of block `n1` to block `n2`.

    `cut            ( -- )`

    Deletes everything on the line, starting from the current
    position.

    `d              ( [| ...] -- )`

    Deletes given text (or last found text).

    `e              ( -- )`

    Deletes last found text.

    `f              ( [| ...] -- )`

    Searches given text (or contents of the find-buffer) in current
    line.

    `i              ( [| ...] -- )`

    Inserts given text (or contents of the insert-buffer) at current
    position.

    `index          ( n1 n2 -- )`

    Shows first lines of blocks in given range.

    `k              ( -- )`

    Swaps contents of insert- and find-buffer.

    `l              ( -- )`

    Clears window and lists current screen.

    `n              ( -- )`

    Lists next screen.

    `p              ( [| ...] -- )`

    Replaces current line with given text (or contents of the
    insert-buffer).

    `r              ( [| ...] -- )`

    Replaces last found text with given text (or contents of the
    insert-buffer).

    `s              ( n [| ...] -- n )`

    Searches given text (or contents of find-buffer) in current
    screen and all blocks up to and including `n`.

    `show           ( n1 n2 -- )`

    Lists blocks in the given range.

    `t              ( n -- )`

    Selects line `n`.

    `till           ( [| ...] -- )`

    Erases all text from the current position to the position where
    the given text (or the contents of the find-buffer) is found in
    the current line.

    `u              ( [| ...] -- )`

    Inserts given text (or contents of insert-buffer) below the
    current line, shifting remaining lines down.

    `wipe           ( -- )`

    Blanks the current screen.

    `x              ( -- )`

    Removes current line and stores it in the insertion-buffer, scrolls
    lines below up.


Tips and Tricks
---------------

- Creating a custom *image*

  To create a personal development system that contains more than the
  core wordset, use `save-image` to write the dictionary to a file:

        include stuff.f   \ extras
        include blocks.f  \ block-words
        include ed.f      \ block-editor
        save-image myimage

  This generates `myimage`, that, when loaded, holds the same
  dictionary that was in effect at the time the image was saved. To
  load this image enter:

        load-image myimage

  Or, if you want to use it with the front-end, start the latter like
  this:

        forth -image myimage

- Image files can be executed directly, as they are prefixes with
  a *she-bang* line of the form `#!/usr/bin/env ff`. A custom
  application can be created like this:

        $ ff
        : foo ." hello, world!" cr ;
         ok
        :noname ['] foo is startup ; execute
         ok
        save-image hello
         ok
        bye
        $ chmod +x hello
        $ hello
        hello, world!
        $

- By using the `-ff` front-end option, nothing prevents you from
  invoking a forth-interpreter on another machine:

        forth -ff "ssh <remotemachine> ff"

  Alternatively, put this into your `~/.forth`:

        set forth "ssh <remotemachine> ff"

- The initial heap/dictionary space is allocated to roughly 10 MB.  To
  change this setting, modify the value of the constant `HEAP_SIZE` in
  `ff-<ARCH>.s` and rebuild everything. In the same manner the sizes
  of the data- and return stack can be adjusted by modifying
  `SSTACK_SIZE` or `RSTACK_SIZE`.

- Don't use tab (ASCII 9) characters - they are not treated as
  any other non-whitespace character.


List of all available words
---------------------------

    !              ( x a -- )                       primitive
    !+             ( a1 x -- a2 )                   optional

    ?exit          ( f -- )                         optional

    "              ( ..." -- a n )                  

    #              ( u1 -- u2 )                     
    #>             ( u1 -- a n )                    
    #s             ( u -- n )                       

    '              ( <word> -- xt )                 

    (              ( ...) -- )         immediate    
    (+loop)        ( n -- )                         primitive
    (:)            ( -- )                           primitive
    (.)            ( n1 -- a n2 )                   
    (?abort)       ( f a n -- )
    (abort)        ( ... -- )
    (constant)     ( -- x )                         primitive
    (deferred)     ( -- )                           primitive
    (do)           ( n1 n2 -- )                     primitive
    (else)         ( -- )                           primitive
    (if)           ( n1 -- )                        primitive
    (literal)      ( -- n )                         primitive
    (loop)         ( -- )                           primitive
    (sliteral)     ( -- a n )                       primitive
    (variable)     ( -- a)                          primitive

    *              ( n1 n2 -- n3 )                  primitive

    +              ( n1 n2 -- n3 )                  primitive
    +!             ( n a -- )
    +loop          ( n -- )            immediate

    ,              ( x -- )
    ,"             ( | ..." -- )                    optional

    -              ( n1 n2 -- n3 )                  primitive
    -trailing      ( a n1 -- a n2 )                 optional

    .              ( n -- )
    ."             ( | ..." -- )       immediate
    .(             \( | ...) -- )      immediate    optional
    .buffers       ( -- )                           optional
    .s             ( -- )
    .r             ( n1 n2 -- )

    /              ( n1 n2 -- n3 )                  
    /mod           ( n1 n2 -- n3 n4 )               primitive
    /string        ( a1 n1 -- a2 n2 )               optional

    0<             ( n -- f )
    0<>            ( n -- f )
    0=             ( n -- f )
    0>             ( n -- f )

    1+             ( n1 -- n2 )
    1-             ( n1 -- n2 )
    2*             ( n1 -- n2 )
    2/             ( n1 -- n2 )
    2@             ( a -- x y )
    2!             ( x y a -- )
    2>r            ( x y -- )
    2drop          ( x y -- )
    2dup           ( x y -- x y x y )
    2nip           ( x y z -- z )
    2r>            ( -- x y )
    2swap          ( x y z q -- z q x y )

    :              ( | <word> -- )
    :noname        ( | ... -- xt )                  optional

    ;              ( -- )              immediate

    <              ( n1 n2 -- f )                   primitive
    <#             ( -- )
    <>             ( n1 n2 -- f )
    <builds        ( | <word> -- )

    =              ( n1 n2 -- f )                   primitive

    >              ( n1 n2 -- f )                   primitive
    >body          ( a1 -- a2 )
    >in            ( -- a )
    >limit         ( -- a )
    >r             ( x -- )                         primitive

    ?              ( a -- )
    ?do            ( n1 n2 -- )
    ?dup           ( x -- x [x] )
    ?stack         ( -- )

    @              ( a -- x )                       primitive
    @+             ( a1 -- a2 x )                   optional

    [              ( -- )
    [']            ( | <word> -- xt )  immediate
    [char]         ( | <char> -- c )   immediate

    \              ( | ... -- )        immediate

    ]              ( -- )              immediate

    _end           ( -- a )                         primitive
    _start         ( -- a )                         primitive

    abort          ( ... -- )          deferred
    abort"         ( f | ..." -- )     immediate
    abs            ( n -- u )
    accept         ( a n1 -- n2 )
    again          ( -- )              immediate
    align          ( -- )
    aligned        ( a1 -- a2 )
    allot          ( n -- )
    also           ( -- )                           optional
    and            ( n1 n2 -- n3 )                  primitive
    args           ( -- a )

    b              ( -- )                           editor
    base           ( -- a )
    begin          ( -- )              immediate
    bl             ( -- c )
    bload          ( a n -- )
    blank          ( a n -- )
    blk            ( -- a )
    block          ( n -- a )
    boot           ( -- )
    bounds         ( a1 n -- a2 a1 )                optional
    buffer         ( n -- a )
    buffer:        ( n | <word> -- )                optional
    bye            ( -- )                           

    c!             ( c a -- )                       primitive
    c,             ( c -- )
    c@             ( a -- c )                       primitive
    c"             ( | ..." -- a )                  
    cas            ( a x y -- f )                   primitive
    case           ( x -- )                         optional
    cell+          ( a1 -- a2 )
    cells          ( n1 -- n2 )
    char           ( | <char> -- c )
    clear          ( ... -- )                       primitive
    close-file     ( fd -- ior )
    cmove          ( a1 a2 n -- )                   primitive
    cmove>         ( a1 a2 n -- )                   primitive
    cold           ( ... -- )         
    command        ( | <word> -- )   deferred       optional
    compare        ( a1 n1 a2 n2 -- n3 )
    constant       ( x | <word> -- x )
    context        ( -- a )                         optional
    copy           ( n1 n2 -- )                     editor
    count          ( a1 -- a2 n )
    cr             ( -- )
    crash          ( -- )
    create         ( | <word> -- )
    current        ( -- )                           primitive
    cut            ( -- )                           editor

    d              ( | ... -- )                     editor
    decimal        ( -- )
    defer          ( | <word> -- )
    definitions    ( -- )                           optional
    depth          ( -- u )
    do             ( n1 n2 -- )      immediate
    does>          ( | ... -- a )
    drop           ( x -- )                         primitive
    dump           ( a n -- )
    dup            ( x -- x x )                     primitive

    e              ( -- )                           editor
    editor         ( -- )                           editor
    else           ( -- )            immediate
    emit           ( c -- )
    emits          ( c n -- )
    empty-buffers  ( -- )
    endcase        ( -- )                           optional
    endof          ( -- )                           optional
    erase          ( a n -- )
    execute        ( xt -- )                        primitive
    exit           ( -- )                           primitive

    f              ( | ... -- )                     editor
    false          ( -- 0 )
    fill           ( a n c -- )
    find           ( a -- a 0 | xt 1 | xt -1 )
    flush          ( -- )
    forth          ( -- )                           optional
    forget         ( | <word> -- )                  optional

    h              ( -- a )                         primitive
    halt           ( n -- )                         primitive
    heaptop        ( -- a )                         primitive
    here           ( -- a )
    hex            ( -- )
    hold           ( c -- )

    i              ( -- n )                         primitive
    i              ( | ... -- )                     editor
    if             ( f -- )          immediate
    immediate      ( -- )
    include        ( | <fname> -- )                 primitive
    index          ( n1 n2 -- )
    interpret      ( -- )
    invert         ( n1 -- n2 )                     
    is             ( xt | <word> -- ) immediate

    j              ( -- n )                         primitive
    join           ( -- )                           editor 

    k              ( -- )                           editor
    key            ( -- c )

    l              ( -- )                           editor
    list           ( n -- )                         editor
    literal        ( n -- )
    load           ( n -- )                         editor
    load-image     ( | <fname> -- )
    loop           ( -- )           immediate
    lshift         ( n1 u -- n2 )                   primitive

    max            ( n1 n2 -- n1 | n2 )
    marker         ( | <word> -- )                  optional
    min            ( n1 n2 -- n1 | n2 )
    mmap           ( a1 -- a2 )                     primitive
    mod            ( n1 n2 -- n3 )

    n              ( -- )                           editor
    negate         ( n1 -- n2 )
    next-screen    ( -- )                           optional
    nip            ( x y -- y )
    noop           ( -- )                           optional
    number         ( a n1 -- n2 -1 | a n1 0 )

    of             ( x -- )                         optional
    off            ( a -- )
    on             ( a -- )
    only           ( -- )                           optional
    open-file      ( a n1 n2 -- fd ior )
    or             ( n1 n2 -- n3 )                  primitive
    order          ( -- )                           optional
    over           ( x y -- x y x )                 primitive

    p              ( | ... -- )                     editor
    pad            ( -- a )
    page           ( -- )
    parse          ( c | ... -- a )
    perform        ( a -- )                         optional
    postpone       ( | <word> -- )                  optional
    pick           ( ... n -- x )
    previous       ( -- )                           optional
    previous-screen ( -- )                           optional
    prompt         ( -- )             deferred

    query          ( -- )
    quit           ( ... -- )

    r              ( | ... -- )                     editor
    r/o            ( -- n )
    r/w            ( -- n )
    r>             ( -- x )                         primitive
    r@             ( -- x )                         primitive
    random         ( -- n )                         optional
    read-file      ( a n1 fd -- n2 ior )
    recurse        ( -- )
    refill         ( -- f )
    repeat         ( -- )           immediate
    reposition-file ( n fd -- ior )
    reset          ( -- )                           primitive
    restore-input  ( ... n -- )
    reveal         ( -- )
    rfind          ( xt -- a|0 )                    optional
    rot            ( n1 -- n2 )
    rshift         ( n1 u -- n2 )                   primitive
    rshifta        ( n1 u -- n2 )                   primitive

    s              ( n | ... -- n )                 editor
    s"             ( | ..." -- a n ) immediate
    s0             ( -- a )
    s@             ( -- a )                         primitive
    save-image     ( | <fname> -- )
    save-input     ( -- ... n )
    scan           ( a1 n1 c -- a2 n2 )             optional
    scr            ( -- a )                         editor
    search         ( a1 n1 a2 n2 -- a3 n3 f )
    see            ( | <word> -- )                  optional
    seed           ( -- a )                         optional
    show           ( n1 n2 -- )                     editor
    sign           ( n -- )
    signum         ( n1 -- n2 )
    skip           ( a1 n1 c -- a2 n2 )             optional
    sliteral       ( | ..." -- )
    smudge         ( -- )
    space          ( -- )
    spaces         ( n -- )
    startup        ( -- )          deferred
    state          ( -- a )
    string         ( c | ... -- )
    string,        ( a n -- )                       optional
    swap           ( x y -- y x )

    t              ( n -- )                         editor
    then           ( -- )          immediate
    th             ( n1 -- n2 )                     optional
    thru           ( n1 n2 -- )                     editor
    tib            ( -- a )
    till           ( | ... -- )                     editor
    true           ( -- -1 )
    tuck           ( x y -- y x y )
    type           ( a n -- )

    u              ( | ... -- )                     editor
    u.             ( u -- )
    under+         ( n1 n2 n3 -- n4 n2 )            optional
    unloop         ( -- )          immediate        primitive
    until          ( f -- )        immediate
    unused         ( -- u )
    update         ( -- )
    utfdecode      ( a1 -- a2 c )
    utfencode      ( a c -- a n )

    variable       ( | <word> -- )
    vocabulary     ( | <word> -- )                  optional

    w/o            ( -- n )
    while          ( f -- )        immediate
    wipe           ( -- )                           editor
    within         ( n1 n2 n3 -- f )
    word           ( c | <word> -- a )
    words          ( -- )                           optional
    write-file     ( a n fd -- ior )

    x              ( -- )                           editor
    xor            ( n1 n2 -- n3 )


Frontend Key-bindings 
---------------------

The key-bindings match mostly the standard key-bindings in Tcl/Tk's `text`
widget:

    Delete                 Toggle "hold" mode
    <Arrow>                Move insertion point
    Sh-<Arrow>             Move insertion point + extend selection
    C-Left, C-Right        Move insertion point by words
    C-Sh-Left, C-Sh-Right  Move insertion point by words + extend selection
    C-Sh-Up, C-Sh-Down     Move by paragraphs + extend selection
    Next, Prior            Move vertically one screenful
    Sh-Next, Sh-Prior      Move screenful + extend selection
    C-Next, C-Prior        Move horizontally one page without changing point
    C-a                    Move to beginning of line
    Home                   Move to beginning of text
    C-e                    Move to end of line
    End                    Move to end of text
    C-Space                Set selection anchor
    C-Sh-Space             Select from anchor to insertion point
    C-/                    Select all text
    C-d                    Delete selection or one character
    Backspace              Delete selection or last character
    M-d                    Delete next word
    C-k                    Cut rest of line
    M-Backspace            Delete previous word
    C-w                    Cut selection
    C-t                    Transpose characters
    C-z                    Undo
    C-Sh-z                 Redo
    C-+                    Increase font size
    C--                    Decrease font size
    Return                 Send current line to forth and insert newline
    C-Up                   List previous block
    C-Down                 List next block
    Escape                 Terminate
    Tab                    Indent or tab
    Alt-w                  Copy current selection
    Insert                 Insert unicode codepoint (hex or named character)
    F1                     Show this text
    


Memory map
----------

    +-----------------------+-----------+-------------------------------------+
    | Area                  |      Size | Contains                            |
    +-----------------------+-----------+-------------------------------------+
    | machine code words    |           | ".text" section ("_start"..."_end") |
    | primitive dictionary  |           | start of ".data" section            |
    | core dictionary       |           |                                     |
    | system variables      |        16 |                                     |
    | tib                   |      1024 |                                     |
    | wordbuffer            |       256 |                                     |
    | heapspace             |           | start of ".bss" section             |
    | :                     |           |                                     |
    |                       |           |                                     |
    | insert buffer         |      1024 | if editor is loaded                 |
    | find buffer           |      1024 |                                     |
    | buffer space          | 16 x 1024 | if block-words are loaded           |
    | return stack          |      4096 |                                     |
    | parameter stack       |      4096 |                                     |
    | end of heap           |           | Contents of variable "s0"           |
    +-----------------------+-----------+-------------------------------------+


Register Usage
--------------

    +----------------+---------------+--------------+----------------------------------+
    | Forth register | i386 register | ARM register | Meaning                          |
    +----------------+---------------+--------------+----------------------------------+
    | TOS            | eax           | r0           | Top of stack                     |
    | SP             | esp           | r13          | Data-stack ptr (grows downwards) |
    | RP             | ebp           | r14          | Return-stack ptr (grows upwards) |
    | AP             | esi           | r12          | Address-pointer                  |
    | W              | edi           | r11          | "Work" register (holds CFA)      |
    |                | ebx, ecx, edx | r1 - r5      | Temporaries                      |
    +----------------+---------------+--------------+----------------------------------+


License
-------

    Copyright (c) 2015, Felix L. Winkelmann
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:
    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
    3. The name of the authors may not be used to endorse or promote products
       derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


Contact
-------

If you have questions, suggestions, want to report bugs or comment on
the system, please don't hesitate to contact me at 

  ` felix <at> call-with-current-continuation  <dot> org `


[1]: http://nasm.us/

[2]: http://www.gnu.org/software/binutils/

[3]: http://www.taygeta.com/forth/dpans.html

[4]: http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html#mmap_arg_struct

[5]: http://bitbucket.org/bunny351/ff