-
Notifications
You must be signed in to change notification settings - Fork 0
/
bf-interpreter.asm
320 lines (238 loc) · 7.58 KB
/
bf-interpreter.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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
extern _malloc, _calloc, _fdopen, _fprintf, _getchar, _putchar, _fopen, _fseek, _ftell, _rewind, _fgetc, _fclose
%define STDERR 2
%define SEEK_END 2
%define EOF -1
%define BF_MEMORY_CELL_AMOUNT 30000
%define BF_PROGRAM_END 255
%define JUMP_PAST_CODE 91
%define JUMP_BACK_CODE 93
section .data
write_mode db "w", 0
read_mode db "r", 0
bfprogram_jump_table times 43 dd run_program_loop_end,
dd bfprogram_memory_inc,
dd bfprogram_input,
dd bfprogram_memory_dec,
dd bfprogram_output,
times 13 dd run_program_loop_end,
dd bfprogram_pointer_left,
dd run_program_loop_end,
dd bfprogram_pointer_right,
times 28 dd run_program_loop_end,
dd bfprogram_jump_past,
dd run_program_loop_end,
dd bfprogram_jump_back,
times 34 dd run_program_loop_end,
times 127 dd run_program_loop_end, ; 128 (127 + next line) invalid ASCII characters
dd run_program_done ; if jump address is 255 (BF_PROGRAM_END), then we're done
error_noargument db "Fatal: No argument was provided.", 0
error_notexist db "Fatal: The file does not exist.", 0
error_outofmemory db "Fatal: The Operating System does not have enough memory available.", 0
section .bss
file_name resd 1
bf_program_size resd 1
bf_program resd 1
bf_memory resd 1
section .text
global _main
_main:
mov ebp, esp ; save original stack pointer
;
; read command line arguments
;
mov eax, [ebp + 4] ; argc
cmp eax, 1
je error_exit_noargument
mov eax, [ebp + 8] ; *argv
mov eax, [eax + 4] ; argv[1]
mov [file_name], eax
;
; open file
;
push read_mode
push eax
call _fopen
add esp, 8
test eax, eax
jz error_exit_notexist
mov edi, eax ; store file pointer
;
; get file size
;
push SEEK_END
push 0
push edi
call _fseek
add esp, 12
push edi
call _ftell
add esp, 4
inc eax ; reserve one extra byte for the BF_PROGRAM_END code
mov [bf_program_size], eax
;
; rewind file
;
push edi
call _rewind
add esp, 4
;
; read Brainfuck program from file
;
push dword [bf_program_size]
call _malloc
add esp, 4
test eax, eax
jz error_exit_outofmemory
mov [bf_program], eax
mov esi, eax
store_program_loop:
push edi
call _fgetc
add esp, 4
cmp eax, EOF ; stop reading when end of file reached
jz short store_program_done
mov [esi], al
inc esi
jmp short store_program_loop
store_program_done:
mov [esi], byte BF_PROGRAM_END ; store program end special code
;
; close file
;
push edi
call _fclose
add esp, 4
;
; 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
error_exit_noargument:
push write_mode
push 2
call _fdopen
add esp, 8
push error_noargument
push eax
call _fprintf
add esp, 8
mov eax, -1
jmp short exit
error_exit_notexist:
push write_mode
push 2
call _fdopen
add esp, 8
push error_notexist
push eax
call _fprintf
add esp, 8
mov eax, -2
jmp short exit
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, -3
jmp short exit
normal_exit:
mov eax, 0
exit:
ret