to make a division operator that handles negative numbers as you
probably expect it to (see the previous section):
: ABS DUP 0< IF -1 * THEN ; ( n -- |n| )
: 2ABS ABS SWAP ABS SWAP ; ( n1 n2 -- |n1| |n2| )
: ?DIFF-SIGNS 0< SWAP 0< XOR ; ( n1 n2 -- f )
: DIVIDE 2DUP 2ABS / ROT> ?DIFF-SIGNS
IF -1 * THEN ; ( n1 n2 -- quot )
( take the absolute value of both numbers before
dividing. if only one of the two was negative,
multiply the result by -1 to undo the absolute-
value-ing. )
fun fact, ?DIFF-SIGNS is re-used from our solution to
a similar problem with comparison
operators.
stack manipulation
see the "Paramater Stack" section in collapse os's doc/dict.txt.
note that ROT> [rot greater-than] is the same as what's called
-ROT [minus rot] in some other forths.
if you're following along with starting forth, chapter 2 has you
solve some problems that expect you to use 2SWAP and 2OVER. given that
collapse os does not have these words, you can solve these using the
return stack, which is introduced in chapter 5. if you'd like to solve
them now, here's a 2SWAP and a 2OVER you can use:
: 2SWAP >R ROT> R> ROT> ; ( d1 d2 -- d2 d1 )
: 2OVER 2>R 2DUP 2R> 2SWAP ; ( d1 d2 -- d1 d2 d1 )
comparison operators
see the "Logic" section in collapse os's doc/dict.txt. note that the
flag returned will be 1 for true or 0 for false, whereas many forths use
negative 1 for true.
using 0< [zero less-than], you can make comparison operators that
will always state a positive number is greater than a negative number
(because the built-in ones treat numbers as unsigned).
here's our go at it:
: ?DIFF-SIGNS 0< SWAP 0< XOR ; ( n1 n2 -- f )
( check whether n1 or n2, but not both, is negative )
: GT DUP ?DIFF-SIGNS IF
DROP 0< IF 0
ELSE 1 THEN
ELSE > THEN ; ( n1 n2 -- f )
( if n1 and n2 have different signs, check which one
is the negative number and say that one is lesser. if
they have the same sign, use the built-in greater-than
operator )
: LT DUP ?DIFF-SIGNS IF
DROP 0< IF 1
ELSE 0 THEN
ELSE < THEN ; ( n1 n2 -- f )
( similar to GT, but the 0 and 1 are switched, and
the > is changed to a < )
: GTE 2DUP GT ROT> = OR ; ( n1 n2 -- f )
: LTE 2DUP LT ROT> = OR ; ( n1 n2 -- f )
( greater-than/less-than or equal )
block 120 includes some "useful little words" that aren't included
in collapse os's basic dictionary, but can be used after loading them
with 120 LOAD
. there are definitions for MIN and MAX
included there, but since they use the built-in greater- and less-than
operators, they also might tell you a negative number is greater than
a positive one. to change this, just replace the greater-than and
less-than symbols in them with your new GT and LT words.
if/else and loops
if you're typing a word definition into the command line and you get
a "br ovfl" (buffer overflow) when you're finished, it could be because
there's a mismatched number of IFs and THENs or DOs and LOOPs in what
you typed.
some forths have ?DO [question-mark do], meaning "do only if the given
number of iterations is greater than 0", and +LOOP [plus loop], which
takes a number to increase the loop counter by rather than just
increasing it by one. collapse os does not. as far as we can figure, to
get the behavior of question-mark do, you just have to enclose a regular
DO in an if-statement. for plus loop, it's probably easier to just use a
BEGIN/UNTIL instead. we might put together some examples to get a better
idea.
to exit the current word being executed, you can use ABORT. if you'd
like to include an error message along with your abort, use ABORT" [abort
quote]—like dot-quote, it prints the following text up to a closing
quotation mark. note that abort-quote does not take anything off
the stack, whereas some forths have it take a flag.
go to part 3 or go to the
table of contents