diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-04-05 07:45:50 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-04-05 07:45:50 -0700 |
| commit | 9b27f0bdc250279a41b46a5b8139f9fad22e59dc (patch) | |
| tree | 009c585afefe1bfdf30a0c09a687dc1e92757bc4 | |
| parent | 122949c6ddf241c63102de643fcd82b474ece987 (diff) | |
implement dot, the function that prints an integer
Force-Push: yes Change-Id: I3e282f1d850dac1ee31fc8ee55ba6edecdacbfca
| -rw-r--r-- | quine.asm | 60 |
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 |