Refactor BrainFuck interpreter to use a Registers class for state management; introduce Lua interpreter with basic structure and register handling.

This commit is contained in:
2025-04-11 21:57:42 +01:00
parent bdacec29ca
commit 81c4f80b71
6 changed files with 81 additions and 45 deletions

View File

@@ -1,6 +1,6 @@
from sys import stdin, stdout from sys import stdin, stdout
from os import PathLike from os import PathLike
from interpreter import Interpreter, opcode from interpreter import Interpreter, Registers, opcode
from pathlib import Path from pathlib import Path
@@ -32,48 +32,62 @@ class BrainFuckByteCodeCompiler:
) )
class BrainFuckRegisters(Registers):
def __init__(self) -> None:
super().__init__()
self.memory_pointer: int = 0
class BrainFuckInterpreter(Interpreter): class BrainFuckInterpreter(Interpreter):
def __init__(self, bits=8, memsize=None) -> None:
super().__init__(bits, memsize)
self._registers: BrainFuckRegisters = BrainFuckRegisters()
def load_program(self, program: bytearray) -> None:
super().load_program(program)
self._registers.memory_pointer = len(program) + 1
@opcode(BrainFuckByteCode[">"]) @opcode(BrainFuckByteCode[">"])
def forward(self): def forward(self):
self._memory_pointer += 1 self._registers.memory_pointer += 1
@opcode(BrainFuckByteCode["<"]) @opcode(BrainFuckByteCode["<"])
def backward(self): def backward(self):
self._memory_pointer -= 1 self._registers.memory_pointer -= 1
@opcode(BrainFuckByteCode["+"]) @opcode(BrainFuckByteCode["+"])
def increment(self): def increment(self):
val = self._memory[self._memory_pointer] val = self._memory[self._registers.memory_pointer]
self._memory[self._memory_pointer] = (val + 1) % 256 self._memory[self._registers.memory_pointer] = (val + 1) % 256
@opcode(BrainFuckByteCode["-"]) @opcode(BrainFuckByteCode["-"])
def decrement(self): def decrement(self):
val = self._memory[self._memory_pointer] val = self._memory[self._registers.memory_pointer]
self._memory[self._memory_pointer] = (val - 1) & 255 self._memory[self._registers.memory_pointer] = (val - 1) & 255
@opcode(BrainFuckByteCode["."]) @opcode(BrainFuckByteCode["."])
def io_in(self): def io_out(self):
stdout.write(chr(self._memory[self._memory_pointer])) stdout.write(chr(self._memory[self._registers.memory_pointer]))
@opcode(BrainFuckByteCode[","]) @opcode(BrainFuckByteCode[","])
def io_out(self): def io_in(self):
stdout.flush() stdout.flush()
self._memory[self._memory_pointer] = ord(stdin.read(1)) self._memory[self._registers.memory_pointer] = ord(stdin.read(1))
@opcode(BrainFuckByteCode["["]) @opcode(BrainFuckByteCode["["])
def loop_start(self): def loop_start(self):
# Ignore opcode if mem_pointer == 0 # Ignore opcode if mem_pointer == 0
if self._memory[self._memory_pointer] > 0: if self._memory[self._registers.memory_pointer] > 0:
pass pass
elif self._memory[self._memory_pointer] == 0: elif self._memory[self._registers.memory_pointer] == 0:
self._program_counter = self.findNext() - 1 self._registers.program_counter = self.findNext() - 1
@opcode(BrainFuckByteCode["]"]) @opcode(BrainFuckByteCode["]"])
def start_end(self): def start_end(self):
self._program_counter = self.findNext(-1) self._registers.program_counter = self.findNext(-1)
def findNext(self, incrementValue: int = 1) -> int: def findNext(self, incrementValue: int = 1) -> int:
search_pointer = self._program_counter + incrementValue search_pointer = self._registers.program_counter + incrementValue
bracket_counter = 1 bracket_counter = 1
while bracket_counter != 0: while bracket_counter != 0:
opcode = self._memory[search_pointer] opcode = self._memory[search_pointer]

View File

@@ -1,3 +1,3 @@
from .__interpreter import Interpreter, opcode from .__interpreter import Interpreter, Registers, opcode
__all__ = ["Interpreter", "opcode"] __all__ = ["Interpreter", "Registers", "opcode"]

View File

@@ -9,7 +9,7 @@ from .util import hexdump
Operation: TypeAlias = str | int Operation: TypeAlias = str | int
Subroutine: TypeAlias = Callable Subroutine: TypeAlias = Callable
OPCODE_HEADER = "__enterpreter__opcode" OPCODE_HEADER = "__interpreter__opcode"
def opcode(opcode: Operation): def opcode(opcode: Operation):
@@ -20,54 +20,60 @@ def opcode(opcode: Operation):
return _helper return _helper
class Registers:
def __init__(self) -> None:
self.program_counter: int = 0
class Memory:
def __init__(self, size: int) -> None:
self.__memory_size: int = size
self.__memory: bytearray = bytearray(self.__memory_size)
def __getitem__(self, idx) -> int:
return self.__memory[idx]
def __setitem__(self, idx, value) -> None:
self.__memory[idx] = value
def dump(self):
return self.__memory
class Interpreter: class Interpreter:
def __init__(self, bits=8, memsize=None) -> None: def __init__(self, bits=8, memsize=None) -> None:
memsize = memsize or 2**bits
self.__bits = bits self.__bits = bits
self.__memory_max_size = 2**self.__bits self.__memory_max_size = 2**self.__bits
self.__memory_size = min(memsize, self.__memory_max_size) self.__memory_size = min(memsize or 2**bits, self.__memory_max_size)
self._memory: Memory = Memory(self.__memory_size)
self._memory = bytearray(self.__memory_size) self._registers: Registers = Registers()
self._memory_pointer: int = 0
self._program_counter: int = 0
self.__operations: dict[Operation, Subroutine] = dict() self.__operations: dict[Operation, Subroutine] = dict()
self.__init_opcodes() self.__init_opcodes()
def __init_opcodes(self): def __init_opcodes(self):
for func_name, func in getmembers( for _, func in getmembers(self, lambda obj: hasattr(obj, OPCODE_HEADER)):
self, lambda obj: hasattr(obj, OPCODE_HEADER) opcode = getattr(func, OPCODE_HEADER)
): self.__operations[opcode] = func
self._register_opcode(getattr(func, OPCODE_HEADER), func)
def _register_opcode(self, opcode: Operation, callback: Subroutine):
self.__operations[opcode] = callback
def is_running(self) -> bool:
return self._memory[self._program_counter] != 0
def run(self) -> None: def run(self) -> None:
try: try:
# Keep running until you reach a null byte # Keep running until you reach a null byte
while self.is_running(): while (opcode := self._memory[self._registers.program_counter]) != 0:
opcode = self._memory[self._program_counter]
self.__operations[opcode]() self.__operations[opcode]()
self._program_counter += 1 self._registers.program_counter += 1
except Exception as e: except Exception as e:
self.dump() self.dump()
print_exception(e) print_exception(e)
def dump(self): def dump(self):
hexdump( hexdump(
data=self._memory, data=self._memory.dump(),
program_counter=self._program_counter, program_counter=self._registers.program_counter,
memory_pointer=self._memory_pointer, memory_pointer=self._registers.memory_pointer
) )
pprint(self.__operations) pprint(self.__operations)
def load_program(self, program: bytearray) -> None: def load_program(self, program: bytearray) -> None:
self._memory[: len(program)] = program[:] self._memory[: len(program)] = program[:]
# Set new pointer immediately after code
self._memory_pointer = len(program) + 1

0
src/lua/__init__.py Normal file
View File

16
src/lua/__lua.py Normal file
View File

@@ -0,0 +1,16 @@
from interpreter import Interpreter, Registers, opcode
class LuaRegisters(Registers):
def __init__(self) -> None:
super().__init__()
class LuaByteCodeInterpreter(Interpreter):
def __init__(self, bits=8, memsize=None) -> None:
super().__init__(bits, memsize)
self._registers = LuaRegisters()
...
def lua():
...

0
src/lua/__main__.py Normal file
View File