collapseos/usage.txt

125 lines
4.5 KiB
Plaintext

Collapse OS usage guide
This document is not meant to be an introduction to Forth, but to instruct the
user about the peculiarities of this Forth implemenation. Be sure to refer to
dictionary.txt for a word reference.
*** DOES>
Used inside a colon definition that itself uses CREATE, DOES> transforms that
newly created word into a "does cell", that is, a regular cell ( when called,
puts the cell's addr on PS), but right after that, it executes words that appear
after the DOES>.
"does cells" always allocate 4 bytes (2 for the cell, 2 for the DOES> link) and
there is no need for ALLOT in colon definition.
At compile time, colon definition stops processing words when reaching the
DOES>.
Example: ": CONSTANT CREATE HERE @ ! DOES> @ ;"
*** Compilation vs meta-compilation
Compilation vs meta-compilation. When you compile a word with "[COMPILE] foo",
its straightforward: It writes down to HERE wither the address of the word or
a number literal.
When you *meta* compile, it's a bit more mind blowing. It fetches the address
of the word specified by the caller, then writes that number as a literal,
followed by a reference to ",".
Example: ": foo [COMPILE] bar;" is the equivalent of ": foo bar ;" if bar is
not an immediate. However, ": foo COMPILE bar ;" is the equivalent of
": foo ['] bar , ;". Got it?
Meta-compile only works with real words, not number literals.
*** I/O
A little word about inputs. There are two kind of inputs: direct and buffered.
As a general rule, we read line in a buffer, then feed words in it to the
interpreter. That's what "WORD" does. If it's at the End Of Line, it blocks and
wait until another line is entered.
KEY input, however, is direct. Regardless of the input buffer's state, KEY will
return the next typed key.
PARSING AND BOOTSTRAP: Parsing number literal is a very "core" activity of
Forth, and therefore generally seen as having to be implemented in native code.
However, Collapse OS' Forth supports many kinds of literals: decimal, hex, char,
binary. This incurs a significant complexity penalty.
What if we could implement those parsing routines in Forth? "But it's a core
routine!" you say. Yes, but here's the deal: at its native core, only decimal
parsing is supported. It lives in the "(parsed)" word. The interpreter's main
loop is initially set to simply call that word.
However, in core.fs, "(parsex)", "(parsec)" and "(parseb)" are implemented, in
Forth, then "(parse)", which goes through them all is defined. Then, "(parsef)",
which is the variable in which the interpreter's word pointer is set, is
updated to that new "(parse)" word.
This way, we have a full-featured (and extensible) parsing with a tiny native
core.
*** Chained comparisons
The unit "cmp.fs" contains words to facilitate chained comparisons with a single
reference number. This allows, for example, to easily express "a == b or a == c"
or "a > b and a < c".
The way those chained comparison words work is that, unlike single comparison
operators, they don't have a "n1 n2 -- f" signature, but rather a "n1 f n2 -- n1
f" signature. That is, each operator "carries over" the reference number in
addition to the latest flag.
You open a chain with "<>{" and you close a chain with "<>}". Then, in between
those words, you can chain operators. For example, to check whether A == B or A
== C, you would write:
A <>{ B &= C |= <>}
The first operator must be of the "&" type because the chain starts with its
flag to true. For example, "<>{ <>}" yields true.
To check whether A is in between B and C inclusively, you would write:
A <>{ B 1 - &> C 1 + &< <>}
*** Addressed devices
The adev unit provides a simple but powerful abstraction over C@ and C!: A@ and
A!. These work the same way as C@ and C! (but for performance reasons, aren't
used in core words), but are indirect calls.
Upon initialization, the default to C@ and C!, but can be set to any word
through A@* and A!*.
On top of that, it provides a few core-like words such as AMOVE.
Let's demonstrate its use through a toy example:
> : F! SWAP 1 + SWAP C! ;
> 8 H@ DUMP
:54 0000 0000 0000 0000 ........
> 9 H@ A!
> 8 H@ DUMP
:54 0900 0000 0000 0000 ........
> ' F! A!* !
> 9 H@ 1 + A!
> 8 H@ DUMP
:54 090a 0000 0000 0000 ........
> H@ H@ 2 + 2 AMOVE
> 8 H@ DUMP
:54 090a 0a0b 0000 0000 ........
>
Of course, you might want to end up using adev in this kind of ad-hoc way to
have some kind of mapping function, but what you'll mostly want to to is to
plug device drivers into those words.