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:
parent
205e2716dd
commit
fb8cbf7219
3 changed files with 27 additions and 5 deletions
|
|
@ -43,7 +43,7 @@ class ZCpuRestart(ZCpuError):
|
||||||
|
|
||||||
class ZCpu:
|
class ZCpu:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, zmem, zopdecoder, zstack, zobjects, zstring, zstreammanager, zui
|
self, zmem, zopdecoder, zstack, zobjects, zstring, zstreammanager, zui, zlexer
|
||||||
):
|
):
|
||||||
self._memory = zmem
|
self._memory = zmem
|
||||||
self._opdecoder = zopdecoder
|
self._opdecoder = zopdecoder
|
||||||
|
|
@ -52,6 +52,7 @@ class ZCpu:
|
||||||
self._string = zstring
|
self._string = zstring
|
||||||
self._streammanager = zstreammanager
|
self._streammanager = zstreammanager
|
||||||
self._ui = zui
|
self._ui = zui
|
||||||
|
self._lexer = zlexer
|
||||||
|
|
||||||
def _get_handler(self, opcode_class, opcode_number):
|
def _get_handler(self, opcode_class, opcode_number):
|
||||||
try:
|
try:
|
||||||
|
|
@ -556,8 +557,10 @@ class ZCpu:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def op_verify(self, *args):
|
def op_verify(self, *args):
|
||||||
"""TODO: Write docstring here."""
|
"""Verify story file checksum. Branch if checksum matches."""
|
||||||
raise ZCpuNotImplemented
|
expected_checksum = self._memory.read_word(0x1C)
|
||||||
|
actual_checksum = self._memory.generate_checksum()
|
||||||
|
self._branch(expected_checksum == actual_checksum)
|
||||||
|
|
||||||
def op_piracy(self, *args):
|
def op_piracy(self, *args):
|
||||||
"""TODO: Write docstring here."""
|
"""TODO: Write docstring here."""
|
||||||
|
|
@ -619,9 +622,22 @@ class ZCpu:
|
||||||
self._memory[text_buffer_addr + 1 + len(text)] = 0
|
self._memory[text_buffer_addr + 1 + len(text)] = 0
|
||||||
|
|
||||||
# Tokenize if parse buffer provided
|
# Tokenize if parse buffer provided
|
||||||
# Note: ZLexer not yet wired up - tokenization will be added when needed
|
|
||||||
if parse_buffer_addr != 0:
|
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):
|
def op_sread_v4(self, *args):
|
||||||
"""TODO: Write docstring here."""
|
"""TODO: Write docstring here."""
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
from . import zlogging
|
from . import zlogging
|
||||||
from .zcpu import ZCpu
|
from .zcpu import ZCpu
|
||||||
|
from .zlexer import ZLexer
|
||||||
from .zmemory import ZMemory
|
from .zmemory import ZMemory
|
||||||
from .zobjectparser import ZObjectParser
|
from .zobjectparser import ZObjectParser
|
||||||
from .zopdecoder import ZOpDecoder
|
from .zopdecoder import ZOpDecoder
|
||||||
|
|
@ -33,6 +34,7 @@ class ZMachine:
|
||||||
self._opdecoder.program_counter = self._mem.read_word(0x06)
|
self._opdecoder.program_counter = self._mem.read_word(0x06)
|
||||||
self._ui = ui
|
self._ui = ui
|
||||||
self._stream_manager = ZStreamManager(self._mem, self._ui)
|
self._stream_manager = ZStreamManager(self._mem, self._ui)
|
||||||
|
self._lexer = ZLexer(self._mem)
|
||||||
self._cpu = ZCpu(
|
self._cpu = ZCpu(
|
||||||
self._mem,
|
self._mem,
|
||||||
self._opdecoder,
|
self._opdecoder,
|
||||||
|
|
@ -41,6 +43,7 @@ class ZMachine:
|
||||||
self._stringfactory,
|
self._stringfactory,
|
||||||
self._stream_manager,
|
self._stream_manager,
|
||||||
self._ui,
|
self._ui,
|
||||||
|
self._lexer,
|
||||||
)
|
)
|
||||||
|
|
||||||
# --------- Public APIs -----------
|
# --------- Public APIs -----------
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ class ZMachineOpcodeTests(TestCase):
|
||||||
Mock(), # string
|
Mock(), # string
|
||||||
Mock(), # stream manager
|
Mock(), # stream manager
|
||||||
self.ui,
|
self.ui,
|
||||||
|
Mock(), # lexer
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_op_nop(self):
|
def test_op_nop(self):
|
||||||
|
|
@ -356,6 +357,7 @@ class ZMachineObjectOpcodeTests(TestCase):
|
||||||
self.string,
|
self.string,
|
||||||
Mock(), # stream manager
|
Mock(), # stream manager
|
||||||
self.ui,
|
self.ui,
|
||||||
|
Mock(), # lexer
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_op_get_sibling_with_sibling(self):
|
def test_op_get_sibling_with_sibling(self):
|
||||||
|
|
@ -536,6 +538,7 @@ class ZMachineComplexOpcodeTests(TestCase):
|
||||||
Mock(), # string
|
Mock(), # string
|
||||||
Mock(), # stream manager
|
Mock(), # stream manager
|
||||||
self.ui,
|
self.ui,
|
||||||
|
Mock(), # lexer
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_op_sread_v3_basic_input(self):
|
def test_op_sread_v3_basic_input(self):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue