-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterpreter.py
126 lines (96 loc) · 3.7 KB
/
interpreter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import argparse
import os
from typing import List, Optional
class CowInterpreter:
available_commands = ["moo", "mOo", "moO", "mOO", "Moo", "MOo", "MoO", "MOO", "OOO", "MMM", "OOM", "oom"]
def __init__(self) -> None:
super().__init__()
self._cells: List[int] = [0 for _ in range(30000)]
self._commands: List[int] = []
self._ptr: int = 0
self._cmd_ptr: int = 0
self._register: Optional[int] = None
self._commands_to_functions = {
0: self._handle_loop_end,
1: self._move_to_prev_cell,
2: self._move_to_next_cell,
3: self._handle_current_as_instruction,
4: self._print_or_read_char,
5: self._decriment_current_block,
6: self._increment_current_block,
7: self._handle_loop_start,
8: self._zero_current_cell,
9: self._copy_or_paste_register,
10: self._print_int,
11: self._read_int
}
def interpret(self, code: str):
filtered_cmds = filter(lambda cmd: cmd in self.available_commands, code.split())
mapped_cmds = map(lambda cmd: self.available_commands.index(cmd), filtered_cmds)
self._commands = list(mapped_cmds)
self._ptr = 0
while self._cmd_ptr < len(self._commands):
self._handle_command(self._commands[self._cmd_ptr])
self._cmd_ptr += 1
def _handle_command(self, current_cmd):
self._commands_to_functions[current_cmd]()
def _handle_loop_start(self):
curr_cell = self._cells[self._ptr]
if curr_cell == 0:
le = self._get_loop_end(self._cmd_ptr)
self._ptr = le
def _handle_loop_end(self):
ls = self._get_loop_start(self._cmd_ptr)
self._ptr = ls - 1
def _zero_current_cell(self):
self._cells[self._ptr] = 0
def _move_to_prev_cell(self):
self._ptr -= 1
def _move_to_next_cell(self):
self._ptr += 1
def _handle_current_as_instruction(self):
cell_cmd = self._cells[self._ptr]
if 0 > cell_cmd >= len(self.available_commands) or cell_cmd == 3:
raise Exception(f"Invalid command {cell_cmd} when executing mOO command")
self._handle_command(cell_cmd)
def _print_or_read_char(self):
cell = self._cells[self._ptr]
if cell == 0:
self._read_char()
else:
self._print_char()
def _decriment_current_block(self):
self._cells[self._ptr] -= 1
def _increment_current_block(self):
self._cells[self._ptr] += 1
def _copy_or_paste_register(self):
if self._register is None:
self._register = self._cells[self._ptr]
else:
self._cells[self._ptr] = self._register
self._register = None
def _print_int(self):
print(self._cells[self._ptr], end='')
def _read_int(self):
self._cells[self._ptr] = int(input(">>>"))
def _read_char(self):
self._cells[self._ptr] = ord(input(">>>")[0])
def _print_char(self):
print(chr(self._cells[self._ptr]), end='')
def _get_loop_end(self, cmd_ptr):
pass
def main(args: argparse.Namespace):
filename = args.input
if not os.path.isfile(filename):
raise FileNotFoundError(f"File '{filename}' does not exists")
file = open(filename, "rt")
if not file.readable():
raise BlockingIOError("Provided file is not readable")
lines = '\n'.join(file.readlines())
interpreter = CowInterpreter()
interpreter.interpret(lines)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("input", help="Input file to be interpreted")
args = parser.parse_args()
main(args)