Cześć, przerabiam sobie książkę gynvaela (jak ktoś nie czytał to polecam :) ) i jestem na etapie tworzenia interpretera języka brainfuck. Wybrałem język python i bazowałem dość mocno na vm'ce z tego rozdziału, ale to tak na marginesie.
Byłbym wdzięczny jakby ktoś doświadczony rzucił okiem pod kątem jakości kodu i ogólnego podejścia do problemu, czy jest to optymalne rozwiązanie czy można coś zrobić lepiej. Z góry dzięki za każdą opinie :)
BF (main class)
import sys
from bf_memory import BFMemory
from bf_instr import BF_INSTR
class BF:
def __init__(self):
self.mem = BFMemory()
self.mem_counter = 0
self.terminated = False
self.program = bytearray(30000)
self.instr = BF_INSTR
self.program_counter = 0
self.start_of_the_loop = 0
self.loop_counter = 0
def crash(self):
self.terminated = True
print("The program has crashed.")
def load_program_from_file(self, addr, name):
with open(name, 'rb') as f:
data = f.read(30*1024)
return self.mem.store_many(addr, data)
def run(self):
while self.mem.fetch_byte(self.mem_counter) in BF_INSTR and not self.terminated:
self.instr[self.mem.fetch_byte(self.mem_counter)](self)
self.mem_counter += 1
if __name__ == '__main__':
if len(sys.argv) != 2:
print("usage: bf.py <filename>")
sys.exit(1)
bf = BF()
bf.load_program_from_file(0, sys.argv[1])
bf.run()
class BFMemory
class BFMemory:
def __init__(self):
self._mem = bytearray(30*1024) # 30 KB memory size
def store_many(self, addr, array):
if addr + len(array) - 1 >= len(self._mem):
return False
for i, value in enumerate(array):
self._mem[addr + i] = value
return True
def fetch_byte(self, addr):
if addr < 0 or addr >= len(self._mem):
return None
return self._mem[addr]
Instructions
import sys
def INC(bf):
bf.program[bf.program_counter] = (bf.program[bf.program_counter] + 1) & 0xff
def DEC(bf):
bf.program[bf.program_counter] = (bf.program[bf.program_counter] - 1) & 0xff
# stdout
def WRITE_STDOUT(bf):
sys.stdout.write(chr(bf.program[bf.program_counter]))
# stdin
def READ_STDIN(bf): #
ch = sys.stdin.read(1)
bf.program[bf.program_counter] = ord(ch)
# go left
def DEC_PTR(bf):
if bf.program_counter < len(bf.program):
bf.program_counter -= 1
else:
bf.crash()
# go right
def INC_PTR(bf):
if bf.program_counter < len(bf.program):
bf.program_counter += 1
else:
bf.crash()
# open loop
def OPEN_LOOP(bf):
bf.start_of_the_loop = bf.mem_counter
bf.loop_counter = bf.program_counter
# close loop
def CLOSE_LOOP(bf):
if bf.program[bf.loop_counter] > 0:
bf.mem_counter = bf.start_of_the_loop
BF_INSTR = {
0x2b: INC, # +
0x2d: DEC, # -
0x2e: WRITE_STDOUT, # .
0x2c: READ_STDIN, # ,
0x5b: OPEN_LOOP, # [
0x5d: CLOSE_LOOP, # ]
0x3c: DEC_PTR, # <
0x3e: INC_PTR # >
}