-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterpreter.py
152 lines (123 loc) · 5.36 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
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
import sys
EOF, PLUS, MINUS, RIGHT, LEFT, LOOPSTART, LOOPEND, INPUT, OUTPUT = "EOF", "PLUS", "MINUS", "RIGHT", "LEFT", "LOOPSTART", "LOOPEND", "INPUT", "OUTPUT"
class Token(object):
def __init__(self, type, val):
self.type = type # One of the types in line 3 (PLUS,MINUS, etc.)
self.val = val # The tokens value, for example '+'
class Interpreter(object):
def __init__(self, text):
self.text = text # The input code
self.pos = 0 # Current position in input code, e.g. "+++-++-++"
self.current_token = None # Current selected token
self.loops = {} # Keeps track of loops
self.looppointers = []
self.currentpointer = 0 # Current position in list of pointers, e.g. ([0][0]>[0]<[0][0]) (> and < as pointer)
self.memory = { # Maybe not the best way to do it, list of all cells and its values, e.g. the default is just '[0]'
0: 0
}
def error(self, num): # Creates an rror with error number
raise Exception(f'Error while interpreting (Errno:{num})')
def next_token(self): # Proceeds to next token
text = self.text.strip().replace(" ", "")
if self.pos > len(text) - 1:
return Token(EOF, None)
current_char = text[self.pos]
match current_char:
case "+":
token = Token(PLUS, current_char)
self.pos += 1
return token
case "-":
token = Token(MINUS, current_char)
self.pos += 1
return token
case ">":
token = Token(RIGHT, current_char)
self.pos += 1
return token
case "<":
token = Token(LEFT, current_char)
self.pos += 1
return token
case "[":
token = Token(LOOPSTART, current_char)
self.pos += 1
return token
case "]":
token = Token(LOOPEND, current_char)
self.pos += 1
return token
case ".":
token = Token(OUTPUT, current_char)
self.pos += 1
return token
case ",":
token = Token(INPUT, current_char)
self.pos += 1
return token
self.error(1)
def findloops(self): # Does some magic to get all the loops and write them down
used = []
pointer = 0
code = self.text.strip().replace(" ", "")
for i in range(len(code)):
starts,ends = 0,0
if i < len(code):
if code[i] == ">":
pointer += 1
if code[i] == "<":
pointer -= 1
if code[i] == "[" and i not in used:
for b in range(i,len(code)):
if b in used:
break
match code[b]:
case "[":
starts+=1
case "]":
ends+=1
if starts == ends:
self.loops[b] = i,pointer
used.append(i)
used.append(b)
break
def expr(self): # Main logic, processes and fulfills the actual functions of the tokens
self.findloops()
#self.loopends.reverse()
output = ""
usrinput = ""
self.current_token = self.next_token()
while self.current_token.type != EOF:
if self.current_token.type == LOOPEND:
if self.pos-1 in self.loops:
if self.memory[self.loops[self.pos-1][1]] != 0 :
self.pos = self.loops[self.pos-1][0]
if self.current_token.type == PLUS:
self.memory[self.currentpointer] += 1
if self.current_token.type == MINUS:
self.memory[self.currentpointer] -= 1
if self.current_token.type == OUTPUT:
output += (chr(self.memory[self.currentpointer]))
if self.current_token.type == INPUT:
if usrinput == "":
usrinput += input(">")
self.memory[self.currentpointer] = ord(usrinput[0])
usrinput = usrinput.replace(usrinput[0],"")
if self.current_token.type == RIGHT:
self.currentpointer += 1
if not self.currentpointer in self.memory:
self.memory[self.currentpointer] = 0
if self.current_token.type == LEFT:
self.currentpointer -= 1
if not self.currentpointer in self.memory:
self.memory[self.currentpointer] = 0
self.current_token = self.next_token()
return output
def main(file):
with open(file) as readfile:
global inputfile
inputfile = readfile.read()
interpreter = Interpreter(inputfile)
print(interpreter.expr())
if __name__ == '__main__':
main(sys.argv[-1]) # Takes a file from the command line as input, something like "python3 main.py brainfk.bf"