-
Notifications
You must be signed in to change notification settings - Fork 0
/
bf-interpreter-console.asm
303 lines (215 loc) · 7.53 KB
/
bf-interpreter-console.asm
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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
extern _malloc, _calloc, _printf, _fdopen, _fprintf, _scanf, _getchar, _putchar
%define STDERR 2
%define NEWLINE_CODE 10
%define BF_MEMORY_CELL_AMOUNT 30000
%define BF_PROGRAM_END 255
%define JUMP_PAST_CODE 91
%define JUMP_BACK_CODE 93
section .data
format_int db "%d", 0
write_mode db "w", 0
msg_memoryamount db "Enter how much memory (in bytes) your Brainfuck program needs: ", 0
msg_bfprogram db "Enter your Brainfuck program (use Enter exclusively to continue): ", 0
bfprogram_jump_table times 43 dd bfprogram_invalidop,
dd bfprogram_memory_inc,
dd bfprogram_input,
dd bfprogram_memory_dec,
dd bfprogram_output,
times 13 dd bfprogram_invalidop,
dd bfprogram_pointer_left,
dd bfprogram_invalidop,
dd bfprogram_pointer_right,
times 28 dd bfprogram_invalidop,
dd bfprogram_jump_past,
dd bfprogram_invalidop,
dd bfprogram_jump_back,
times 34 dd bfprogram_invalidop,
times 127 dd bfprogram_invalidop, ; 128 (127 + next line) invalid ASCII characters
dd run_program_done ; if jump address is 255 (BF_PROGRAM_END), then we're done
error_outofmemory db "Fatal: The Operating System does not have enough memory available.", 0
error_programsize db "Fatal: The given Brainfuck program exceeded the given memory size.", 0
error_invalidop db "Fatal: An unsupported Brainfuck operation was found.", 0
section .bss
max_bf_program_size resd 1
bf_program resd 1
bf_program_size resd 1
bf_memory resd 1
section .text
global _main
_main:
mov ebp, esp ; save original stack pointer
;
; store Brainfuck program from console input
;
push msg_memoryamount
call _printf
add esp, 4
lea eax, [ebp - 4]
push eax
push format_int
call _scanf
add esp, 8
mov eax, [ebp - 4]
mov [max_bf_program_size], eax
inc eax ; reserve one extra byte for the BF_PROGRAM_END code
push eax
call _malloc
add esp, 4
test eax, eax
jz error_exit_outofmemory
mov [bf_program], eax
call _getchar ; consume newline
push msg_bfprogram
call _printf
add esp, 4
mov edi, [max_bf_program_size]
xor ebx, ebx
mov esi, [bf_program]
store_program_loop:
call _getchar
cmp eax, NEWLINE_CODE ; stop reading on newline
jz short store_program_done
cmp ebx, edi ; error if exceeded program size
jz error_exit_programsize
mov [esi + ebx], al
inc ebx
jmp short store_program_loop
store_program_done:
mov [esi + ebx], byte BF_PROGRAM_END ; store program end special code
mov [bf_program_size], ebx
;
; zero-initialize BF memory cells
;
push dword 1
push BF_MEMORY_CELL_AMOUNT
call _calloc
add esp, 8
test eax, eax
jz error_exit_outofmemory
mov [bf_memory], eax
;
; run the BF program
;
mov esi, eax ; current memory address
mov edi, [bf_program] ; current program address
run_program_loop:
movzx eax, byte [edi]
jmp [bfprogram_jump_table + 4*eax] ; addresses are dword, ASCII is translated to byte offsets
run_program_loop_end:
inc edi
jmp short run_program_loop
run_program_done:
jmp normal_exit
bfprogram_pointer_right:
inc esi
jmp run_program_loop_end
bfprogram_pointer_left:
dec esi
jmp run_program_loop_end
bfprogram_memory_inc:
mov al, [esi]
inc al
mov [esi], al
jmp run_program_loop_end
bfprogram_memory_dec:
mov al, [esi]
dec al
mov [esi], al
jmp run_program_loop_end
bfprogram_output:
mov al, [esi]
push eax ; safe to do because eax is 000000xxh before the prior mov
call _putchar
add esp, 4
jmp run_program_loop_end
bfprogram_input:
call _getchar
mov [esi], al
jmp run_program_loop_end
bfprogram_jump_past:
mov al, [esi]
test al, al ; check if memory cell is zero
jnz run_program_loop_end ; if not zero, move to next instruction
;
; find matching ]
;
mov ebx, 1 ; when counter reaches zero the ] is found where we need to jump past
bfprogram_jump_past_loop:
inc edi
mov al, [edi]
cmp al, JUMP_PAST_CODE
jz short bfprogram_jump_past_loop_found_jump_past
cmp al, JUMP_BACK_CODE
jz short bfprogram_jump_past_loop_found_jump_back
jmp short bfprogram_jump_past_loop
bfprogram_jump_past_loop_found_jump_past:
inc ebx
jmp short bfprogram_jump_past_loop
bfprogram_jump_past_loop_found_jump_back:
dec ebx
test ebx, ebx
jz run_program_loop_end ; jumped over matching ]
jmp short bfprogram_jump_past_loop
bfprogram_jump_back:
mov al, [esi]
test al, al ; check if memory cell is zero
jz run_program_loop_end ; if zero, move to next instruction
;
; find matching [
;
mov ebx, 1 ; when counter reaches zero the [ is found where we need to jump back to
bfprogram_jump_back_loop:
dec edi
mov al, [edi]
cmp al, JUMP_BACK_CODE
jz short bfprogram_jump_back_loop_found_jump_back
cmp al, JUMP_PAST_CODE
jz short bfprogram_jump_back_loop_found_jump_past
jmp short bfprogram_jump_back_loop
bfprogram_jump_back_loop_found_jump_back:
inc ebx
jmp short bfprogram_jump_back_loop
bfprogram_jump_back_loop_found_jump_past:
dec ebx
test ebx, ebx
jz run_program_loop_end ; jumped back to matching [
jmp short bfprogram_jump_back_loop
bfprogram_invalidop:
jmp error_exit_invalidop
error_exit_outofmemory:
push write_mode
push 2
call _fdopen
add esp, 8
push error_outofmemory
push eax
call _fprintf
add esp, 8
mov eax, -1
jmp short exit
error_exit_programsize:
push write_mode
push 2
call _fdopen
add esp, 8
push error_programsize
push eax
call _fprintf
add esp, 8
mov eax, -2
jmp short exit
error_exit_invalidop:
push write_mode
push 2
call _fdopen
add esp, 8
push error_invalidop
push eax
call _fprintf
add esp, 8
mov eax, -3
jmp short exit
normal_exit:
mov eax, 0
exit:
ret