Urieladd files5f2c91910 years agoHistory
1058 lines · 37.7 KB · Text
RawDownload
 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-codedaddresses, together with binaries containing the target-specific machine codeof 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` onPlan 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 areavaialble 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 exitsthe front-end. The function keys can be bound to text that is either inserted at the currentposition, or (if it ends with a newline) immediately executed. To bind a key toa 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 theblock 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 inthe file `ed.f`.  See below for a list of available editorcommands. Blocks are stored in a file called `blockfile`, which mustreside in the current working directory. Note that the editor needsthe 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 editedblock (`scr`): the *insertion-buffer* and the *find-buffer*. Theformer is used in commands that add or insert text, the latter holdstext that is searched. The editor is provided in source form in the file `ed.f`. TheANS 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`. 

Lines 1–500 of 1058.