104 lines
2.9 KiB
Python
104 lines
2.9 KiB
Python
from sys import stdin, stdout
|
|
from os import PathLike
|
|
from interpreter import Interpreter, 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 BrainFuckInterpreter(Interpreter):
|
|
@opcode(BrainFuckByteCode[">"])
|
|
def forward(self):
|
|
self._memory_pointer += 1
|
|
|
|
@opcode(BrainFuckByteCode["<"])
|
|
def backward(self):
|
|
self._memory_pointer -= 1
|
|
|
|
@opcode(BrainFuckByteCode["+"])
|
|
def increment(self):
|
|
val = self._memory[self._memory_pointer]
|
|
self._memory[self._memory_pointer] = (val + 1) % 256
|
|
|
|
@opcode(BrainFuckByteCode["-"])
|
|
def decrement(self):
|
|
val = self._memory[self._memory_pointer]
|
|
self._memory[self._memory_pointer] = (val - 1) & 255
|
|
|
|
@opcode(BrainFuckByteCode["."])
|
|
def io_in(self):
|
|
stdout.write(chr(self._memory[self._memory_pointer]))
|
|
|
|
@opcode(BrainFuckByteCode[","])
|
|
def io_out(self):
|
|
stdout.flush()
|
|
self._memory[self._memory_pointer] = ord(stdin.read(1))
|
|
|
|
@opcode(BrainFuckByteCode["["])
|
|
def loop_start(self):
|
|
# Ignore opcode if mem_pointer == 0
|
|
if self._memory[self._memory_pointer] > 0:
|
|
pass
|
|
elif self._memory[self._memory_pointer] == 0:
|
|
self._program_counter = self.findNext() - 1
|
|
|
|
@opcode(BrainFuckByteCode["]"])
|
|
def start_end(self):
|
|
self._program_counter = self.findNext(-1)
|
|
|
|
def findNext(self, incrementValue: int = 1) -> int:
|
|
search_pointer = self._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)
|