-
Notifications
You must be signed in to change notification settings - Fork 2
/
parse.py
192 lines (170 loc) · 6.87 KB
/
parse.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/env python3
from argparse import ArgumentParser, RawDescriptionHelpFormatter
from signal import SIGINT, signal
from readchar import readchar
from sys import version_info, stdout
from time import sleep
from os import path, system, name
import constants
if version_info.major != 3:
raise(EnvironmentError(constants.UNSUPPORTED_VERSION))
class Parser(object):
"""
The parser Class
Args:
file (string): What file should i execute?
debug (float): Should i debug?
intify (bool): Print as an int or char
no_warnings (bool): Should i print the warnings?
size (int): What is the maximum size of each cell
"""
def __init__(self, file=None, debug=False, intify=False, no_warnings=False, size=255):
"""Summary
Args:
file (string, required)
debug (bool, optional)
intify (bool, optional)
no_warnings (bool, optional)
size (int, optional
"""
super(Parser, self).__init__()
if not file:
raise(EnvironmentError(constants.NO_FILE))
bracket = 0
self.debug = None
self.program = str()
self.intify = intify
self.no_warnings = no_warnings
self.maxCellSize = size
if debug == None:
self.debug = 0.1
elif debug < 0:
self.debug = False
elif debug > 0:
self.debug = debug
try:
with open(file) as f:
extension = path.splitext(file)[1]
program = f.read()
if extension.lower() != ".bf" and not self.no_warnings:
print(constants.BF_FILES)
except Exception:
raise(EnvironmentError(constants.NO_FILE))
letters = ['[', ']', '+', '-', ',', '.', '<', '>']
for char in program:
if char in letters:
self.program += char
if char == '[':
bracket += 1
elif char == ']':
bracket -= 1
self.program += ' '
if bracket and not self.no_warnings:
print(constants.LOOP_WARNING)
def parse(self):
try:
signal(SIGINT, lambda s, f: (
stdout.flush(constants.CTRL_C),
exit(1)))
prgPointer = 0
pointer = 0
tape = [0]
prints = ""
cells = ""
# with output(initial_len=6, interval=0) as output_lines:
while prgPointer < len(self.program):
if self.debug:
sleep(self.debug)
cells = ""
for c in tape:
cells += f"{str(c).zfill(len(str(self.maxCellSize)))} "
self.clear_screen()
print(f" ")
print(f"Output: {prints}")
print(f"Tape: {cells}")
print("Ptr: {}^".format(
(" " * (len(str(self.maxCellSize)) + 1)) * pointer))
print(
f"Program: {self.program[prgPointer - 1:prgPointer + 71]}")
print(" ^")
else:
print(f"Output: {prints}", end="\r")
if self.program[prgPointer] == '>':
pointer += 1
if pointer >= len(tape):
tape.append(0)
elif self.program[prgPointer] == '<':
pointer -= 1
if pointer < 0:
raise(EnvironmentError(constants.TAPE_ERROR))
elif self.program[prgPointer] == '+':
tape[pointer] += 1
if tape[pointer] > self.maxCellSize + 1:
tape[pointer] = 0
elif self.program[prgPointer] == '-':
tape[pointer] -= 1
if tape[pointer] < 0:
tape[pointer] = self.maxCellSize
elif self.program[prgPointer] == '.':
if not self.intify:
prints += chr(tape[pointer])
else:
prints += str(int(tape[pointer]))
elif self.program[prgPointer] == ',':
print("Input: ", end='\r')
inp = readchar()
tape[pointer] = ord(inp.decode())
elif self.program[prgPointer] == '[':
if tape[pointer] == 0:
bracket = 0
prgPointer += 1
while prgPointer < len(self.program):
if self.program[prgPointer] == ']' and bracket == 0:
break
if self.program[prgPointer] == '[':
bracket += 1
elif self.program[prgPointer] == ']':
bracket -= 1
prgPointer += 1
elif self.program[prgPointer] == ']':
if tape[pointer] != 0:
bracket = 0
prgPointer -= 1
while prgPointer >= 0:
if self.program[prgPointer] == '[' and bracket == 0:
break
if self.program[prgPointer] == ']':
bracket += 1
elif self.program[prgPointer] == '[':
bracket -= 1
prgPointer -= 1
prgPointer += 1
except Exception as e:
print(e)
raise(EnvironmentError(constants.UNKNOWN_ERROR))
@staticmethod
def clear_screen():
"""
Clear the terminal screen, OS aware.
"""
# Windows
if name == 'nt':
_ = system('cls')
# Mac/Linux
else:
_ = system('clear')
if __name__ == '__main__':
prs = ArgumentParser(prog=constants.PROGRAM_NAME, formatter_class=RawDescriptionHelpFormatter,
description=(constants.PARSER_MSG), epilog=constants.EPILOG)
prs.add_argument("file", help=constants.FILE_HELP, type=str)
prs.add_argument("-s", "--size", help=constants.SIZE_HELP,
default=255, type=int, dest="size", metavar="Size")
prs.add_argument("-i", "--intify",
help=constants.INTIFY_HELP, action='store_true')
prs.add_argument("-d", "--debug", dest="debug", metavar="Sec", type=float,
nargs='?', default=-1, required=False, help=constants.DEBUG_HELP)
prs.add_argument("--no_warnings", action='store_true',
help=constants.NO_WARNINGS_HELP)
args = prs.parse_args()
Parser(args.file, args.debug, args.intify,
args.no_warnings, args.size).parse()