+( Standard words for manipulating BASE. )
+: DECIMAL ( -- ) 10 BASE ! ;
+: HEX ( -- ) 16 BASE ! ;
+
+(
+ The standard FORTH word . (DOT) is very important. It takes the number at the top
+ of the stack and prints it out. However first I'm going to implement some lower-level
+ FORTH words:
+
+ U.R ( u width -- ) which prints an unsigned number, padded to a certain width
+ U. ( u -- ) which prints an unsigned number
+ .R ( n width -- ) which prints a signed number, padded to a certain width.
+
+ For example:
+ -123 6 .R
+ will print out these characters:
+ <space> <space> - 1 2 3
+
+ In other words, the number padded left to a certain number of characters.
+
+ The full number is printed even if it is wider than width, and this is what allows us to
+ define the ordinary functions U. and . (we just set width to zero knowing that the full
+ number will be printed anyway).
+
+ Another wrinkle of . and friends is that they obey the current base in the variable BASE.
+ BASE can be anything in the range 2 to 36.
+)
+: U.R ( u width -- )
+ ( DROP XXX )
+ BASE @ /MOD ( width rem quot )
+ DUP 0<> IF ( if quotient <> 0 then )
+ RECURSE ( print the quotient )
+ ELSE
+ DROP ( drop the zero quotient )
+ THEN
+
+ ( print the remainder )
+ DUP 10 < IF
+ '0' ( decimal digits 0..9 )
+ ELSE
+ 10 - ( hex and beyond digits A..Z )
+ 'A'
+ THEN
+ +
+ EMIT
+;
+
+( U. is easy to define in terms of U.R Note the trailing space. )
+: U. 0 U.R SPACE ;
+
+( .R is easy, we just need to print the sign and then call U.R )
+: .R ( n width -- )
+ SWAP ( width n )
+ DUP 0< IF
+ '-' EMIT ( print the sign )
+ NEGATE ( negate the number so we can use U.R )
+ SWAP 1- ( n width-1 )
+ ELSE
+ SWAP ( n width )
+ THEN
+ DROP ( XXX )
+ U.R
+;
+
+( Finally we can define word . in terms of .R, with a trailing space. )
+: . 0 .R SPACE ;
+
+( ? fetches the integer at an address and prints it. )
+: ? @ . ;
+