Files
Interpreters/src/brainfuck/__brainfuck.py

118 lines
3.4 KiB
Python

from sys import stdin, stdout
from os import PathLike
from interpreter import Interpreter, Registers, opcode
from pathlib import Path
BrainFuckByteCode = {
">": 1,
"<": 2,
"+": 3,
"-": 4,
".": 5,
",": 6,
"[": 7,
"]": 8,
}
class BrainFuckByteCodeCompiler:
def load_file(self, file: PathLike):
self.source_file: PathLike = file
self.load(bytearray(Path(file).read_bytes()))
def load(self, data: bytearray):
self.source_data: bytearray = data
def compile(self) -> bytearray:
return bytearray(
BrainFuckByteCode[c]
for byte in self.source_data
if (c := chr(byte)) in BrainFuckByteCode
)
class BrainFuckRegisters(Registers):
def __init__(self) -> None:
super().__init__()
self.memory_pointer: int = 0
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[">"])
def forward(self):
self._registers.memory_pointer += 1
@opcode(BrainFuckByteCode["<"])
def backward(self):
self._registers.memory_pointer -= 1
@opcode(BrainFuckByteCode["+"])
def increment(self):
val = self._memory[self._registers.memory_pointer]
self._memory[self._registers.memory_pointer] = (val + 1) % 256
@opcode(BrainFuckByteCode["-"])
def decrement(self):
val = self._memory[self._registers.memory_pointer]
self._memory[self._registers.memory_pointer] = (val - 1) & 255
@opcode(BrainFuckByteCode["."])
def io_out(self):
stdout.write(chr(self._memory[self._registers.memory_pointer]))
@opcode(BrainFuckByteCode[","])
def io_in(self):
stdout.flush()
self._memory[self._registers.memory_pointer] = ord(stdin.read(1))
@opcode(BrainFuckByteCode["["])
def loop_start(self):
# Ignore opcode if mem_pointer == 0
if self._memory[self._registers.memory_pointer] > 0:
pass
elif self._memory[self._registers.memory_pointer] == 0:
self._registers.program_counter = self.findNext() - 1
@opcode(BrainFuckByteCode["]"])
def start_end(self):
self._registers.program_counter = self.findNext(-1)
def findNext(self, incrementValue: int = 1) -> int:
search_pointer = self._registers.program_counter + incrementValue
bracket_counter = 1
while bracket_counter != 0:
opcode = self._memory[search_pointer]
if opcode == BrainFuckByteCode["["]:
bracket_counter += incrementValue
elif opcode == BrainFuckByteCode["]"]:
bracket_counter -= incrementValue
search_pointer += incrementValue
return search_pointer
def bf(program_path: PathLike, bits=8, mem=None) -> BrainFuckInterpreter:
bf_c = BrainFuckByteCodeCompiler()
bf_c.load_file(program_path)
program = bf_c.compile()
bf_e = BrainFuckInterpreter(bits=bits, memsize=mem)
bf_e.load_program(program)
bf_e.run()
return bf_e
if __name__ == "__main__":
bf(Path("examples", "HelloWorld.bf"))
bf(Path("examples", "GameOfLife.bf"), bits=16, mem=2**16)
bf(Path("examples", "Mandlebrot.bf"), bits=16, mem=2**16)