Implement op_verify and wire ZLexer into sread for Zork 1

op_verify now performs actual checksum validation against the header
instead of raising NotImplemented. ZLexer is injected into ZCpu and
sread tokenizes input into the parse buffer per the V3 spec.
This commit is contained in:
Jared Miller 2026-02-09 20:57:15 -05:00
parent 205e2716dd
commit fb8cbf7219
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
3 changed files with 27 additions and 5 deletions

View file

@ -43,7 +43,7 @@ class ZCpuRestart(ZCpuError):
class ZCpu:
def __init__(
self, zmem, zopdecoder, zstack, zobjects, zstring, zstreammanager, zui
self, zmem, zopdecoder, zstack, zobjects, zstring, zstreammanager, zui, zlexer
):
self._memory = zmem
self._opdecoder = zopdecoder
@ -52,6 +52,7 @@ class ZCpu:
self._string = zstring
self._streammanager = zstreammanager
self._ui = zui
self._lexer = zlexer
def _get_handler(self, opcode_class, opcode_number):
try:
@ -556,8 +557,10 @@ class ZCpu:
pass
def op_verify(self, *args):
"""TODO: Write docstring here."""
raise ZCpuNotImplemented
"""Verify story file checksum. Branch if checksum matches."""
expected_checksum = self._memory.read_word(0x1C)
actual_checksum = self._memory.generate_checksum()
self._branch(expected_checksum == actual_checksum)
def op_piracy(self, *args):
"""TODO: Write docstring here."""
@ -619,9 +622,22 @@ class ZCpu:
self._memory[text_buffer_addr + 1 + len(text)] = 0
# Tokenize if parse buffer provided
# Note: ZLexer not yet wired up - tokenization will be added when needed
if parse_buffer_addr != 0:
pass # TODO: add tokenization when ZLexer is integrated
max_words = self._memory[parse_buffer_addr]
tokens = self._lexer.parse_input(text)
num_words = min(len(tokens), max_words)
self._memory[parse_buffer_addr + 1] = num_words
offset = 0
for i in range(num_words):
word_str, dict_addr = tokens[i]
# Find word position in text
pos = text.find(word_str, offset)
word_len = len(word_str)
base = parse_buffer_addr + 2 + (i * 4)
self._memory.write_word(base, dict_addr)
self._memory[base + 2] = word_len
self._memory[base + 3] = pos + 1 # 1-indexed from start of text buffer
offset = pos + word_len
def op_sread_v4(self, *args):
"""TODO: Write docstring here."""

View file

@ -7,6 +7,7 @@
from . import zlogging
from .zcpu import ZCpu
from .zlexer import ZLexer
from .zmemory import ZMemory
from .zobjectparser import ZObjectParser
from .zopdecoder import ZOpDecoder
@ -33,6 +34,7 @@ class ZMachine:
self._opdecoder.program_counter = self._mem.read_word(0x06)
self._ui = ui
self._stream_manager = ZStreamManager(self._mem, self._ui)
self._lexer = ZLexer(self._mem)
self._cpu = ZCpu(
self._mem,
self._opdecoder,
@ -41,6 +43,7 @@ class ZMachine:
self._stringfactory,
self._stream_manager,
self._ui,
self._lexer,
)
# --------- Public APIs -----------

View file

@ -107,6 +107,7 @@ class ZMachineOpcodeTests(TestCase):
Mock(), # string
Mock(), # stream manager
self.ui,
Mock(), # lexer
)
def test_op_nop(self):
@ -356,6 +357,7 @@ class ZMachineObjectOpcodeTests(TestCase):
self.string,
Mock(), # stream manager
self.ui,
Mock(), # lexer
)
def test_op_get_sibling_with_sibling(self):
@ -536,6 +538,7 @@ class ZMachineComplexOpcodeTests(TestCase):
Mock(), # string
Mock(), # stream manager
self.ui,
Mock(), # lexer
)
def test_op_sread_v3_basic_input(self):