123 lines
3.2 KiB
Python
Executable file
123 lines
3.2 KiB
Python
Executable file
#!/usr/bin/python3
|
|
import collections
|
|
import ctypes
|
|
import re
|
|
import sys
|
|
|
|
|
|
class Mixin:
|
|
def __add__(self, other):
|
|
return self.value + other
|
|
|
|
def __sub__(self, other):
|
|
return self.value - other
|
|
|
|
def __radd__(self, other):
|
|
return self.value + other
|
|
|
|
def __rsub__(self, other):
|
|
return self.value - other
|
|
|
|
def __iadd__(self, other):
|
|
self.value += other
|
|
return self
|
|
|
|
def __isub__(self, other):
|
|
self.value -= other
|
|
return self
|
|
|
|
def __eq__(self, other):
|
|
return self.value == other
|
|
|
|
def __hash__(self):
|
|
return hash(self.value)
|
|
|
|
|
|
class Byte(Mixin, ctypes.c_byte):
|
|
pass
|
|
|
|
|
|
class UByte(Mixin, ctypes.c_ubyte):
|
|
pass
|
|
|
|
Int = lambda x: x
|
|
|
|
TYPE = Int
|
|
|
|
|
|
class Machine:
|
|
def __init__(self, program):
|
|
self.program = program
|
|
cells = {}
|
|
self.cells = collections.defaultdict(lambda: TYPE(0), cells)
|
|
self.data_pointer = TYPE(0)
|
|
self.instruction_pointer = 0
|
|
|
|
self.command_map = {
|
|
'>': self.increment_data_pointer,
|
|
'<': self.decrement_data_pointer,
|
|
'+': self.increment_cell,
|
|
'-': self.decrement_cell,
|
|
'.': self.print_cell,
|
|
',': self.set_cell,
|
|
'[': self.loop_start,
|
|
']': self.loop_end
|
|
}
|
|
|
|
def increment_data_pointer(self):
|
|
self.data_pointer += 1
|
|
|
|
def decrement_data_pointer(self):
|
|
self.data_pointer -= 1
|
|
|
|
def increment_cell(self):
|
|
self.cells[self.data_pointer] += 1
|
|
|
|
def decrement_cell(self):
|
|
self.cells[self.data_pointer] -= 1
|
|
|
|
def print_cell(self):
|
|
print(chr(self.cells[self.data_pointer]), end='')
|
|
|
|
def set_cell(self):
|
|
self.cells[self.data_pointer] = TYPE(ord(input('=> ')))
|
|
|
|
def loop_start(self):
|
|
if self.cells[self.data_pointer] == 0:
|
|
loop_starts = 0
|
|
self.instruction_pointer += 1
|
|
instruction = self.program[self.instruction_pointer]
|
|
while loop_starts > 0 or instruction != ']':
|
|
if instruction == '[':
|
|
loop_starts += 1
|
|
if instruction == ']':
|
|
loop_starts -= 1
|
|
self.instruction_pointer += 1
|
|
instruction = self.program[self.instruction_pointer]
|
|
|
|
def loop_end(self):
|
|
if self.cells[self.data_pointer] != 0:
|
|
loop_ends = 0
|
|
self.instruction_pointer -= 1
|
|
instruction = self.program[self.instruction_pointer]
|
|
while loop_ends > 0 or instruction != '[':
|
|
if instruction == ']':
|
|
loop_ends += 1
|
|
if instruction == '[':
|
|
loop_ends -= 1
|
|
self.instruction_pointer -= 1
|
|
instruction = self.program[self.instruction_pointer]
|
|
|
|
def run(self):
|
|
while self.instruction_pointer < len(self.program):
|
|
self.command_map[self.program[self.instruction_pointer]]()
|
|
self.instruction_pointer += 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
with open(sys.argv[1], 'r') as f:
|
|
program = re.findall(f"[{re.escape('<>+-.,[]')}]", f.read())
|
|
|
|
machine = Machine(program)
|
|
machine.run()
|
|
print("\nExiting...")
|