go to the table of contents or go back home

notes on forth programming in collapse os

part 02: manipulating numbers

types of numbers

in collapse os, an integer can have any value between -32768 and 32767 signed, or 0 and 65535 unsigned. if you want to work with larger numbers, there are probably ways to get around it, but the os doesn't seem to have much built-in support for things like double-length integers.

collapse os has several words that treat numbers as unsigned, where most other forths would treat them as signed. from a practical standpoint, this means that / [slash, for division] and many of the comparison operators may not work as you expect when handling negative numbers. in the arithmetic and comparison sections below, we'll show you our attempts at making words that work around this.

the aforementioned maximum integer, 65535, is equivalent to FFFF in hexadecimal. collapse os doesn't have a distinct "hex mode" like many forths do, but you can work with hex numbers fairly easily. when typing a hex number, precede it with a $ [dollar sign] so it won't be confused for either a decimal number or a word, like so: $FFFF. if you want to print a number off the stack, use . [dot] to print it in decimal, or .X [dot x] to print it in hexadecimal.

arithmetic operators

in addition to the usual + plus, - minus, * times, and / divided-by operators, here are some other ones collapse os has:

-^ [minus caret]( n1 n2 -- diff ) n2 minus n1
MOD( n1 n2 -- rem ) n1 mod n2 (the remainder of n1 divided by n2)
/MOD [slash mod]( n1 n2 -- rem quot ) the quotient and remainder of n1 divided by n2

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