summary refs log tree commit diff
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-04-05 07:45:50 -0700
committerIrene Knapp <ireneista@irenes.space>2026-04-05 07:45:50 -0700
commit9b27f0bdc250279a41b46a5b8139f9fad22e59dc (patch)
tree009c585afefe1bfdf30a0c09a687dc1e92757bc4
parent122949c6ddf241c63102de643fcd82b474ece987 (diff)
implement dot, the function that prints an integer
Force-Push: yes
Change-Id: I3e282f1d850dac1ee31fc8ee55ba6edecdacbfca
-rw-r--r--quine.asm60
1 files changed, 58 insertions, 2 deletions
diff --git a/quine.asm b/quine.asm
index e4804dc..f2be4fe 100644
--- a/quine.asm
+++ b/quine.asm
@@ -3233,6 +3233,33 @@ defword fetch, 0
   push.qreg rax
   next
 
+; Before we get too deep into it, we also define a few reflection routines
+; that retrieve, or set, the address of either of the two stacks.
+;
+; The result, or the new value, is on the top of the data stack. That's the
+; same as how it works for any other word, but given the metacircular nature
+; of these ones it's easy to get confused about that...
+defword fetch_control_stack, 0
+  dq $ + 8
+  push.qreg rbp
+  next
+defword store_control_stack, 0
+  dq $ + 8
+  pop.qreg rbp
+  next
+defword fetch_value_stack, 0
+  dq $ + 8
+  ; Per Intel's description of PUSH this pushes the old value.
+  push.qreg rsp
+  next
+defword store_value_stack, 0
+  dq $ + 8
+  ; Per Intel's description of POP this reads from the old location, and there
+  ; is no increment applied to the resulting value. See, the description says
+  ; it increments the register then overwrites it, in that order.
+  pop.qreg rsp
+  next
+
 ; Address on top, value second
 ; I might have done it the other way, but this is what Jonesforth does and it
 ; seems reasonable enough.
@@ -3660,8 +3687,37 @@ defword emitstring, 0
 ; In:
 ;   integer
 defword dot, 0
-  ; TODO
-  dq docol, drop, litstring, "(int goes here)", emitstring, exit
+  dq docol
+
+  dq dup, lit, 0, gt, zbranch, 7*8
+  dq lit, -1, mul
+  dq litstring, "-", emitstring
+
+  ; 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 dup, lit, 10, swap, logfloor, lit, 1, add
+
+  ; (input, number of digits remaining)
+  ; This is the start of the loop.
+  dq dup2, lit, 1, sub, lit, 10, swap, pow, divmod, swap, drop
+  ; (input, number of digits remaining, input divided by 10^x appropriately)
+  dq lit, 10, divmod, drop
+
+  ; (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 lit, "0", add, 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, -28*8
+  dq drop, drop, exit
 
 ; In:
 ;   base