summary refs log tree commit diff
diff options
context:
space:
mode:
-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.