summary refs log tree commit diff
path: root/quine.asm
diff options
context:
space:
mode:
Diffstat (limited to 'quine.asm')
-rw-r--r--quine.asm478
1 files changed, 389 insertions, 89 deletions
diff --git a/quine.asm b/quine.asm
index b0fedcb..eaa355b 100644
--- a/quine.asm
+++ b/quine.asm
@@ -2586,6 +2586,305 @@ cold_start:
   dq litstring, "exit", early_find, entry_to_execution_token, early_comma
   dq early_here, fetch, lit, 8, packalign, early_here_store
 
+  dq litstring, "pow", early_create, early_docol_codeword
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 1, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 0, early_comma
+  dq litstring, "=", early_find, entry_to_execution_token, early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 5*8, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 1, early_comma
+  dq litstring, "-", early_find, entry_to_execution_token, early_comma
+  dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "*", early_find, entry_to_execution_token, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "branch", early_find, entry_to_execution_token, early_comma
+  dq lit, -22*8, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  dq litstring, "logfloor", 0, early_create, early_docol_codeword
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 0, early_comma
+  dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, ">unsigned", early_find, entry_to_execution_token, early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 6*8, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 5, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "*", early_find, entry_to_execution_token, early_comma
+  dq litstring, "roll3", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 1, early_comma
+  dq litstring, "+", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 5, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "<", early_find, entry_to_execution_token, early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 8*8, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq litstring, "branch", early_find, entry_to_execution_token, early_comma
+  dq lit, -45*8, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  dq litstring, "logceil", early_create, early_docol_codeword
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 1, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 0, early_comma
+  dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, ">=unsigned", early_find, entry_to_execution_token
+  dq early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 6*8, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 5, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "*", early_find, entry_to_execution_token, early_comma
+  dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 1, early_comma
+  dq litstring, "+", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 5, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "<", early_find, entry_to_execution_token, early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 8*8, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, -45*8, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  ; This was "dotbase_unsigned"
+  dq litstring, "dotbase-unsigned", 0, early_create, early_docol_codeword
+  dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "logfloor", 0, early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 1, early_comma
+  dq litstring, "+", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, ">", early_find, entry_to_execution_token, early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 5*8, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 2*8, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 1, early_comma
+  dq litstring, "-", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 5, early_comma
+  dq litstring, "roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 6, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "pow", early_find, entry_to_execution_token, early_comma
+  dq litstring, "/%", early_find, entry_to_execution_token, early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "roll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 5, early_comma
+  dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
+  dq litstring, "/%", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 10, early_comma
+  dq litstring, ">", early_find, entry_to_execution_token, early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 5*8, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, "0", early_comma
+  dq litstring, "branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 6*8, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 10, early_comma
+  dq litstring, "-", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, "a", early_comma
+  dq litstring, "+", early_find, entry_to_execution_token, early_comma
+  dq litstring, "value@", early_find, entry_to_execution_token, early_comma
+  dq litstring, "emitstring", early_find, entry_to_execution_token
+  dq early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 1, early_comma
+  dq litstring, "-", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 3*8, early_comma
+  dq litstring, "branch", early_find, entry_to_execution_token, early_comma
+  dq lit, -51*8, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "drop", early_find, entry_to_execution_token, early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  dq litstring, "dotbase", early_create, early_docol_codeword
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "dup", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 0, early_comma
+  dq litstring, ">", early_find, entry_to_execution_token, early_comma
+  dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
+  dq lit, 7*8, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, -1, early_comma
+  dq litstring, "*", early_find, entry_to_execution_token, early_comma
+  dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
+  dq litstring, "-", early_comma
+  dq litstring, "emitstring", early_find, entry_to_execution_token
+  dq early_comma
+  dq litstring, "swap", early_find, entry_to_execution_token, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 0, early_comma
+  dq litstring, "dotbase-unsigned", 0, early_find, entry_to_execution_token
+  dq early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  dq litstring, "dot", early_create, early_docol_codeword
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 10, early_comma
+  dq litstring, "dotbase", early_find, entry_to_execution_token, early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  dq litstring, "dothex", early_create, early_docol_codeword
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 16, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 0, early_comma
+  dq litstring, "dotbase-unsigned", 0, early_find, entry_to_execution_token
+  dq early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  dq litstring, "dothex8", early_create, early_docol_codeword
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 16, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 2, early_comma
+  dq litstring, "dotbase-unsigned", 0, early_find, entry_to_execution_token
+  dq early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  dq litstring, "dothex16", 0, early_create, early_docol_codeword
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 16, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 4, early_comma
+  dq litstring, "dotbase-unsigned", 0, early_find, entry_to_execution_token
+  dq early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  dq litstring, "dothex32", 0, early_create, early_docol_codeword
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 16, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 8, early_comma
+  dq litstring, "dotbase-unsigned", 0, early_find, entry_to_execution_token
+  dq early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
+  dq litstring, "dothex64", 0, early_create, early_docol_codeword
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 16, early_comma
+  dq litstring, "lit", early_find, entry_to_execution_token, early_comma
+  dq lit, 16, early_comma
+  dq litstring, "dotbase-unsigned", 0, early_find, entry_to_execution_token
+  dq early_comma
+  dq litstring, "exit", early_find, entry_to_execution_token, early_comma
+  dq early_here, fetch, lit, 8, packalign, early_here_store
+
   dq litstring, "crash", early_create, early_self_codeword, early_here, fetch
   dq hlt
   dq lit, 8, packalign, early_here_store
@@ -2751,16 +3050,14 @@ cold_start:
   ;;;     sorta needs a label but might be avoidable
   ;;;     needs next
   ;;;   execute
-  ;;;     TODO needs heap impl
   ;;;   sys_exit, sys_write
   ;;;     nothing special
   ;;; Forth:
   ;;;   emitstring
   ;;;     stringlen, sys_write, basics
-  ;;;   dot dothex dothex8 dothex16 dothex32 dothex64 dotbase dotbase_unsigned
-  ;;;     TODO needs heap impl
   ;;;   pow logfloor logceil
-  ;;;     TODO needs heap impl
+  ;;;   dotbase_unsigned, dotbase, dot
+  ;;;   dothex, dothex8, dothex16, dothex32, dothex64
   ;;; Assembly:
   ;;;   crash
   ;;;     nothing special
@@ -3881,6 +4178,9 @@ defword emitstring, 0
   dq docol, dup, stringlen, swap, sys_write, exit
 
 
+;   The main word for this next part is "dot"; the stuff preceding it is
+; internals used to implement it.
+;
 ;   Although this could notionally be emitinteger for symmetry, it's
 ; well-known under the name dot and as a single period character, and that
 ; name participates in conventions for names of other things. So, we go with
@@ -3893,91 +4193,6 @@ defword emitstring, 0
 ; doing that avoids having to think about any sort of memory management or
 ; recursion, and lets us stick entirely with the trivial control-flow
 ; constructs we already have.
-;
-; In:
-;   integer to print
-defword dot, 0
-  dq docol, lit, 10, dotbase, exit
-defword dothex, 0
-  dq docol, lit, 16, lit, 0, dotbase_unsigned, exit
-defword dothex8, 0
-  dq docol, lit, 16, lit, 2, dotbase_unsigned, exit
-defword dothex16, 0
-  dq docol, lit, 16, lit, 4, dotbase_unsigned, exit
-defword dothex32, 0
-  dq docol, lit, 16, lit, 8, dotbase_unsigned, exit
-defword dothex64, 0
-  dq docol, lit, 16, lit, 16, dotbase_unsigned, exit
-
-; In:
-;   integer to print
-;   base to print in
-defword dotbase, 0
-  dq docol
-
-  dq swap
-  ; (base, input)
-
-  ; Deal with negative numbers.
-  dq dup, lit, 0, gt, zbranch, 7*8
-  dq lit, -1, mul
-  dq litstring, "-", emitstring
-
-  dq swap, lit, 0, dotbase_unsigned, exit
-
-; In:
-;   integer to print
-;   base to print in
-;   width to zero-pad to
-defword dotbase_unsigned, 0
-  dq docol
-
-  ; (input, base, width)
-  ; Compute how many digits we need to display. Because we use logfloor, the
-  ; logic of always printing at least one digit is already handled for us.
-  dq unroll3, swap, dup2, logfloor, lit, 1, add
-  ; (width, base, input, number of digits if no padding)
-  dq lit, 4, roll, dup2, gt, zbranch, 5*8
-  ; (base, input, number of digits if no padding, width)
-  ; If we're here, we should use the padded width
-  dq swap, drop, branch, 2*8
-  ; (base, input, number of digits if no padding, width)
-  ; If we're here, we should use the unpadded width
-  dq drop
-
-  ; (base, input, number of digits remaining)
-  ; This is the start of the loop.
-  dq dup2, lit, 1, sub
-  ; (base, input, number of digits remaining, input, intermediate value)
-  dq lit, 5, roll, dup, lit, 6, unroll, swap
-  ; (base, input, number of digits remaining, input, base, intermediate value)
-  dq pow, divmod, swap, drop
-  ; (base, input, number of digits remaining,
-  ;  input divided by base^x appropriately)
-  dq lit, 4, roll, dup, lit, 5, unroll
-  ; (base, input, number of digits remaining,
-  ;  input divided by base^x appropriately, base)
-  dq divmod, drop
-
-  ; (base, input, number of digits remaining, current digit)
-  ; We construct a one-character string on the stack, then use a pointer to
-  ; it. It will always contain its own null-termination without us having to
-  ; do anything special to that end.
-  dq dup, lit, 10, gt, zbranch, 5*8
-  dq lit, "0", branch, 6*8
-  dq lit, 10, sub, lit, "a"
-  dq add
-  dq fetch_value_stack, emitstring
-
-  ; We deallocate the string by dropping it.
-  ;
-  ; Saying it like that makes it sound obvious; contemplate it until it feels
-  ; surprising.
-  dq drop
-
-  dq lit, 1, sub
-  dq dup, zbranch, 3*8, branch, -51*8
-  dq drop, drop, drop, exit
 
 ; In:
 ;   base
@@ -4069,6 +4284,91 @@ defword logceil, 0
   ; Nothing else weird going on, so loop.
   dq branch, -45*8
 
+; In:
+;   integer to print
+;   base to print in
+;   width to zero-pad to
+defword dotbase_unsigned, 0
+  dq docol
+
+  ; (input, base, width)
+  ; Compute how many digits we need to display. Because we use logfloor, the
+  ; logic of always printing at least one digit is already handled for us.
+  dq unroll3, swap, dup2, logfloor, lit, 1, add
+  ; (width, base, input, number of digits if no padding)
+  dq lit, 4, roll, dup2, gt, zbranch, 5*8
+  ; (base, input, number of digits if no padding, width)
+  ; If we're here, we should use the padded width
+  dq swap, drop, branch, 2*8
+  ; (base, input, number of digits if no padding, width)
+  ; If we're here, we should use the unpadded width
+  dq drop
+
+  ; (base, input, number of digits remaining)
+  ; This is the start of the loop.
+  dq dup2, lit, 1, sub
+  ; (base, input, number of digits remaining, input, intermediate value)
+  dq lit, 5, roll, dup, lit, 6, unroll, swap
+  ; (base, input, number of digits remaining, input, base, intermediate value)
+  dq pow, divmod, swap, drop
+  ; (base, input, number of digits remaining,
+  ;  input divided by base^x appropriately)
+  dq lit, 4, roll, dup, lit, 5, unroll
+  ; (base, input, number of digits remaining,
+  ;  input divided by base^x appropriately, base)
+  dq divmod, drop
+
+  ; (base, input, number of digits remaining, current digit)
+  ; We construct a one-character string on the stack, then use a pointer to
+  ; it. It will always contain its own null-termination without us having to
+  ; do anything special to that end.
+  dq dup, lit, 10, gt, zbranch, 5*8
+  dq lit, "0", branch, 6*8
+  dq lit, 10, sub, lit, "a"
+  dq add
+  dq fetch_value_stack, emitstring
+
+  ; We deallocate the string by dropping it.
+  ;
+  ; Saying it like that makes it sound obvious; contemplate it until it feels
+  ; surprising.
+  dq drop
+
+  dq lit, 1, sub
+  dq dup, zbranch, 3*8, branch, -51*8
+  dq drop, drop, drop, exit
+
+; In:
+;   integer to print
+;   base to print in
+defword dotbase, 0
+  dq docol
+
+  dq swap
+  ; (base, input)
+
+  ; Deal with negative numbers.
+  dq dup, lit, 0, gt, zbranch, 7*8
+  dq lit, -1, mul
+  dq litstring, "-", emitstring
+
+  dq swap, lit, 0, dotbase_unsigned, exit
+
+; In:
+;   integer to print
+defword dot, 0
+  dq docol, lit, 10, dotbase, exit
+defword dothex, 0
+  dq docol, lit, 16, lit, 0, dotbase_unsigned, exit
+defword dothex8, 0
+  dq docol, lit, 16, lit, 2, dotbase_unsigned, exit
+defword dothex16, 0
+  dq docol, lit, 16, lit, 4, dotbase_unsigned, exit
+defword dothex32, 0
+  dq docol, lit, 16, lit, 8, dotbase_unsigned, exit
+defword dothex64, 0
+  dq docol, lit, 16, lit, 16, dotbase_unsigned, exit
+
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Development utilities ;;;