-
Notifications
You must be signed in to change notification settings - Fork 0
/
bfinterpreter.py
158 lines (137 loc) · 5.18 KB
/
bfinterpreter.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
import sys
import stack
import tape
"""
Brainfuck interpreter
Uses a bre-built map of where to jump as an optimization. Code must be
preprocessed, this is not a repl.
"""
class BFInterpreter():
def __init__(self, tape_size=None):
if (tape_size==None):
self.tape = tape.Tape() # default tape
else:
self.tape = tape.Tape(tape_size)
#self.stack = stack.Stack() # Stack for loops
self.instruction_pointer = 0 # Current instruction
self.program = [] # The program
self.instructions = { ">":self.tape.move_forwards, \
"<":self.tape.move_backwards, \
"+":self.tape.increment, \
"-":self.tape.decrement, \
"[":self.enter_loop, \
"]":self.end_loop, \
".":self.output, \
",":self.input, \
"#":self.debug \
}
self.jump_map = {} # A place to look for corresponding braces
def preprocess_program(self, input_code=None):
"""
Preprocess the brainfuck
Remove comments, split each individual instruction into the
program tape. Clear the memory tape for the next execution.
"""
if (input_code == None):
return;
map(self.program.append, filter((lambda (char): char in self.instructions), input_code))
#self.program.append(False) # Causes interpretation to stop after the program has finished.
self.build_jump_map(self.program)
def build_jump_map(self, input_program):
"""
Build a map of where each "]" has an opening "[".
input_program must be a list of bf commands.
"""
open_bracket_stack = stack.Stack()
for inst, command in enumerate(input_program):
if command in (">","<","+","-",".",",","#",):
# Ignore all normal brainfuck characters.
pass
elif (command=="["):
# We've found one, push it's location onto the stack.
open_bracket_stack.push(inst)
elif (command=="]"):
# We've found a closing one. Map this location to the location
# on the top of the stack
try:
previous_bracket = open_bracket_stack.pop()
self.jump_map[previous_bracket]=inst
self.jump_map[inst] = previous_bracket
except:
#print "Missing open bracket."
raise
#print self.jump_map
def output(self):
"""
Outputs the value of the current cell.
"""
try:
sys.stdout.write(chr(self.tape.current_cell()%256)) # Wrapping fits it into ascii codes
except:
print "Error -001"
def input(self):
"""
Set the current cell to a new value
"""
try:
temp = ord(raw_input())
self.tape.replace(temp)
except:
print "Error -002"
raise
def enter_loop(self):
"""
Do the code goodness for entering a loop.
"""
if (self.tape.current_cell()==0):
# Jump past the end.
self.instruction_pointer = (self.jump_map[self.instruction_pointer])
else:
pass
def end_loop(self):
"""
Jump to the start of the loop if the current cell is not 0.
"""
# if (not self.tape.current_cell()):
# Jump to the start of the loop
self.instruction_pointer = (self.jump_map[self.instruction_pointer]-1)
#else:
# pass
def execute(self):
"""
Execute the cleaned brainfuck program
Will only correctly run after preprocess_program() has been run.
"""
while len(self.program)>(self.instruction_pointer):
self.step()
#self.tape = tape.Tape() # Clear for next time.
def step(self):
"""
Do a single step in a brainfuck program
"""
try:
self.instructions[self.program[self.instruction_pointer]]()
self.instruction_pointer+=1
except tape.TapeError:
#print "Tape underflow, instruction number: "+str(self.instruction_pointer)
raise
def debug(self):
"""
Print debugging information.
"""
print "Tape: "+str(self.tape.tape[:10])+" Current Pointer: "+str(self.tape.pointer)+" Instruction Pointer: "+str(self.instruction_pointer)
def clear_tape(self):
"""
Clear the tape for next round.
"""
self.tape = tape.Tape()
def __str__(self):
"""
A string representation of the interpreter
"""
return str((self.instruction_pointer, self.program,))
def __len__(self):
"""
The length of this brainfuck interpreter
"""
return len(self.tape)