summary refs log tree commit diff
path: root/quine.asm
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2025-11-28 20:19:19 -0800
committerIrene Knapp <ireneista@irenes.space>2025-11-28 20:19:19 -0800
commit445bc67265016be9867127bb5fa38341c5ef9dc0 (patch)
tree4875ee1b53d23c3dd65a1039143cf91aa4fbb907 /quine.asm
parent7504fa3a7926282fffc4b7c9a34073aafeeda7c1 (diff)
add the code to traverse from execution token back to dictionary entry
yay

Force-Push: yes
Change-Id: I21d21df017db6df3c1b60288f0b8c7270f01ded8
Diffstat (limited to 'quine.asm')
-rw-r--r--quine.asm74
1 files changed, 74 insertions, 0 deletions
diff --git a/quine.asm b/quine.asm
index 5d79b36..c13744f 100644
--- a/quine.asm
+++ b/quine.asm
@@ -1259,6 +1259,15 @@ macro rep operation
   end match
 end macro
 
+macro repz operation
+  match =scasb, operation
+    db 0xF3 ; rep prefix
+    db 0xAe ; opcode
+  else
+    assert 0
+  end match
+end macro
+
 macro repnz operation
   match =scasb, operation
     db 0xF2 ; rep prefix
@@ -3318,6 +3327,55 @@ defword stringlen, 0
   push.qreg rdi
   next
 
+; Stack in:
+;   address of final non-null byte at the end of a string
+; Stack out:
+;   backwards string length not including null byte at start
+defword reverse_stringlen, 0
+  dq $ + 8
+  pop.qreg rdi
+
+  mov.qreg.qreg rbx, rdi
+  xor.qreg.qreg rax, rax
+  xor.qreg.qreg rcx, rcx
+  not.qreg rcx
+
+  std
+  repnz scasb
+  cld
+
+  sub.qreg.qreg rbx, rdi
+  sub.qreg.bimm rbx, 1
+
+  push.qreg rbx
+  next
+
+;    If you have a variable-length string followed by alignment padding, and
+; you want to traverse it in reverse, you also need to skip the alignment
+; padding...
+;
+; Stack in:
+;   address of final null byte in alignment padding of total length up to 8
+; Stack out:
+;   number of null bytes (from end) until nearest non-null byte, or 8
+defword reverse_padding_len,  0
+  dq $ + 8
+  pop.qreg rdi
+
+  mov.qreg.qreg rbx, rdi
+  xor.qreg.qreg rax, rax
+  mov.qreg.dimm rcx, 8
+
+  std
+  repz scasb
+  cld
+
+  sub.qreg.qreg rbx, rdi
+  sub.qreg.bimm rbx, 1
+
+  push.qreg rbx
+  next
+
 ;   We make this work using exactly two jump instructions, which is likely the
 ; minimum possible. To avoid relying on labels, we hand-compute the byte
 ; offsets, so every instruction within their ranges is annotated with its
@@ -4834,6 +4892,22 @@ defword entry_to_execution_token, 0
   dq lit, 7, invert, and
   dq exit
 
+defword entry_to_name, 0
+  dq docol
+  dq lit, 10, add
+  dq exit
+
+;   Jonesforth calls this "CFA>". Jonesforth's implementation searches the
+; entire dictionary, since its word header format isn't designed to be
+; traversed in reverse as ours is.
+defword execution_token_to_entry, 0
+  dq docol
+  dq lit, 1, sub
+  dq dup, reverse_padding_len, sub
+  dq dup, reverse_stringlen, sub
+  dq lit, 9, sub
+  dq exit
+
 ;   Allocate space by incrementing "here", and output a word header in it.
 ; Also add it to the "latest" linked list. Use zero as the flag values;
 ; callers that want something else can do that themselves.