This repository has been archived by the owner on Jan 3, 2021. It is now read-only.
/
bfd.asm
executable file
·408 lines (356 loc) · 12.6 KB
/
bfd.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
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
;
; Brainfucked version 1.0.0 - A nice DOS/Windows compiler for brainfuck
;
; Copyright (c) 2002, 2005 by Stefan Partusch
;
; This software is provided 'as-is', without any express or implied
; warranty. In no event will the author be held liable for any damages
; arising from the use of this software.
; For more details see the GNU General Public License!
;
; Brainfucked is assembled with NASM: nasm -fbin -obfd.com bfd.asm
;
; Brainfuck: Equivalent in asm: Opcode (hex/byte):
; + add byte [si], xx 80 04 xx
; inc byte [si] FE 04
; - sub byte [si], xx 80 2C xx
; dec byte [si] FE 0C
; > add si, byte xx 83 C6 xx
; inc si 46
; < sub si, byte xx 83 EE xx
; dec si 4E
; [ cmp byte [si], 0 80 3C 00
; je "]+1" 0F 84 xx xx
; ] jmp "[" E9 xx xx
; . call "11Bh" E8 xx xx
; , call "10Fh" E8 xx xx
;
org 100h
BITS 16
section .data
newLine db 13, 10, 13, 10, "$"
extension db "com", 0
header db "Brainfucked 1.0.0 by S. Partusch$"
errUsage db "Usage: bfd [-n] file", 13, 10, 9, "-n native mode$"
errFile db "ERR: File$"
errBracket db "ERR: Loop$"
wrnBracket db "WRN: Range", 13, 10
success db "File assembled$"
; opInit is (create zero-initialized array of 44000 bytes):
; mov si, 0FE70h / DECSI: dec si / mov byte [si], 0 / cmp si, 0528Fh / jne DECSI / jmp short
opInit db 14, 0BEh, 070h, 0FEh, 04Eh, 0C6h, 004h, 000h, 081h, 0FEh, 08Fh, 052h, 075h, 0F6h, 0EBh
; opProcTxt (CRLF-translation) is:
; read char, store and print it - entry point 10Fh
; END / mov ah, 08h / int 21h / cmp al, 13 / jne STORE / xor al, 7 / STORE: mov [si], al
; print char - entry point 11Bh
; mov ah, 02h / mov dl, [si] / cmp dl, 10 / jne WRITE / xor dl, 7 / int 21h / xor dl, 7 / WRITE: int 21h / ret
; END:
opProcTxt db 33, 020h, 0B4h, 008h, 0CDh, 021h, 03Ch, 00Dh, 075h, 002h, 034h, 007h, 088h, 004h, 0B4h, 002h, 08Ah, 014h, 080h, 0FAh, 00Ah, 075h, 008h, 080h, 0F2h, 007h, 0CDh, 021h, 080h, 0F2h, 007h, 0CDh, 021h, 0C3h
; opProcBin (no CRLF-translation) is:
; read char, store it - entry point 10Fh
; END / mov ah, 08h / int 21h / mov [si], al / ret / nop / nop / nop / nop / nop
; print char - entry point 11Bh
; mov ah, 02h / mov dl, [si] / int 21h / ret / END:
opProcBin db 20, 013h, 0B4h, 008h, 0CDh, 021h, 088h, 004h, 0C3h, 090h, 090h, 90h, 090h, 090h, 0B4h, 002h, 08Ah, 014h, 0CDh, 021h, 0C3h
; opOut is (end program): mov ah, 4Ch / int 21h
opOut db 4, 0B4h, 04Ch, 0CDh, 021h
opPlusInc db 2, 0FEh, 004h ; 0
opMinusDec db 2, 0FEh, 00Ch ; 1
opAnglODec db 1, 04Eh ; 2
opAnglCInc db 1, 046h ; 3
opSqurOpen db 7, 080h, 03Ch, 000h, 00Fh, 084h, 000h, 000h ; 4
opCallSub1 db 1, 0E8h ; 5
opCallSub2 db 1, 0E8h ; 6
opSqurClose db 1, 0E9h ; 7
opPlusAdd db 2, 080h, 004h ; 8
opMinusSub db 2, 080h, 02Ch ; 9
opAnglOSub db 2, 083h, 0EEh ; 10
opAnglCAdd db 2, 083h, 0C6h ; 11
opProc dw opProcTxt
outPos dw 0
commands db "+-<>[.,]"
prevCommand db 0FFh
commCount db 1
squrBrack db 0
anglBrack db 0
anglState db 0
section .bss
fileName resb 130
fileNLen resw 1
fileIn resw 1
fileOut resw 1
addressBuf resw 1
buffer resb 1
section .text
; read command line and get arguments:
;cld
mov si, 80h ; see Program Segment Prefix (PSP) for details
lodsb
cbw ; ax = length of command line
mov cx, ax
mov di, fileName ; si = source/command line, di = destination/fileName
RMV_SPACE:
cmp byte [si], 20h ; ignore leading spaces (ASCII 20h)
jne short RMV_END
inc si
dec cx
jmp short RMV_SPACE
RMV_END:
cmp word [si], "-n"
jne short CONTINUE
add si, 2
sub cx, 2
mov word [opProc], opProcBin
jmp short RMV_SPACE
CONTINUE:
dec cx ; cmp cx, 0
jns short ARGUMENTS_OK
mov si, errUsage
jmp near QUIT_NOFILE
ARGUMENTS_OK:
inc cx
mov word [fileNLen], cx
rep movsb
mov byte [di], cl ; fileName terminates with 0
; open input
mov ax, 3D00h ; al = 00, ah = 3D; open fileName
mov dx, fileName
int 21h
jc near ERROR_FILE
mov word [fileIn], ax
; compute output filename
;mov di, fileName
;add di, [fileNLen] ; go to end of fileName
std
mov cl, [fileNLen]
mov al, "." ; search first "." backwards
repne scasb
dec cx ; cmp cx, 0
js near ERROR_FILE
cld
mov cx, 4
mov si, extension
inc di
inc di
rep movsb
; create output
mov ax, 3C00h ; al = 00, ah = 3C; create file fileName
mov dx, fileName
int 21h
jc near ERROR_FILE
mov word [fileOut], ax
; write output code (i.e. compile)
mov si, opInit
call WRITE_OPCODE
mov si, [opProc]
call WRITE_OPCODE
; translate brainfuck
TRANSLATION:
mov ah, 3Fh ; read input
mov bx, [fileIn]
mov cx, 1
mov dx, buffer
int 21h
jc near ERROR_FILE
;cmp ax, 0 ; number of bytes read
dec ax
js short TRANSLATION_END
; ignore non-brainfuck characters
mov al, byte [buffer]
mov cx, 9
mov di, commands
repne scasb
dec cx ; cmp cx, 0
js short TRANSLATION
; calculate bf-command's number (0-7)
mov bx, di
sub bx, commands
dec bl
mov byte [buffer], bl ; buffer now number between 0 and 7 "+-<>[.,]"
cmp bl, 3
jg short NO_COUNT_CMD_READ ; no "countable" command read
; one of +-<> read
jne short NO_ANGLC ; ">" (number 3) read
inc byte [anglBrack] ; for syntax-check
NO_ANGLC:
cmp bl, 2 ; "<" (number 2) read
jne short ANGL_OK
dec byte [anglBrack] ; syntax-check
jns short ANGL_OK
mov byte [anglState], 0FFh
ANGL_OK:
cmp byte [prevCommand], bl
jne short NEW_COUNT ; new "countable" command read
inc byte [commCount]
jmp short TRANSLATION
NEW_COUNT:
mov al, byte [prevCommand]
call WRITE_COMMAND
mov bl, byte [buffer]
mov byte [prevCommand], bl ; save new command as old command
jmp short TRANSLATION
; one of [.,] read
NO_COUNT_CMD_READ:
mov al, byte [prevCommand]
call WRITE_COMMAND
mov al, byte [buffer]
call WRITE_COMMAND
jmp short TRANSLATION
TRANSLATION_END:
mov si, opOut
call WRITE_OPCODE
mov si, success
QUIT:
mov ah, 3Eh ; close files
mov bx, word [fileIn]
int 21h
mov bx, word [fileOut]
int 21h
; check syntax and set error messages
cmp byte [squrBrack], 0
jne short ERROR_SQURBRACK
cmp byte [anglState], 0
je short QUIT_NOFILE
mov si, wrnBracket
QUIT_NOFILE:
mov dx, header
call PRINTLINE
xor al, al
cmp si, success
je short $+2
inc al ; return code 1 to indicate error
mov dx, si
call PRINTLINE
mov ah, 4Ch ; ah = 4C; end program
int 21h
;----------------------
; subprocedures:
;----------------------
; write to STDIN:
;----------------------
PRINTLINE:
mov ah, 09h
int 21h
mov dx, newLine
int 21h
ret
;----------------------
; errors:
;----------------------
ERROR_FILE:
mov si, errFile
jmp short QUIT_NOFILE
ERROR_SQURBRACK:
mov ah, 41h ; delete file
mov dx, fileName
int 21h
mov si, errBracket
jmp short QUIT_NOFILE
;----------------------
; translation:
;----------------------
COMMAND_SQURCLOSE:
dec byte [squrBrack] ; never < 0
js short QUIT
pop bx ; save return address for WRITE_COMMAND
pop ax
sub ax, 7
push bx
call WRITE_DIFF
; set file pointer to "["+5 (to write offset of end of loop)
mov cx, 0FFFFh
mov dx, [addressBuf]
add dx, 5
mov ax, 4201h
int 21h
; offset to jmp to end of loop: FFFF - (neg_number + 1) = pos_number
mov bx, 0FFF9h ; -6 instead of -1 because of add dx,5
sub bx, word [addressBuf]
mov word [addressBuf], bx
; write offset
mov dx, addressBuf
mov cx, 2
call WRITE_OUTPUT
sub word [outPos], cx
; set file pointer to "normal" position
xor cx, cx
mov dx, [outPos]
mov ax, 4200h
int 21h
jmp short WC_END
WRITE_COMMAND:
cmp al, 0FFh ; no command to write
jne short $+1
ret
cmp byte [commCount], 1 ; "countable" command?
je short NO_COUNT
add al, 8 ; use add/sub version of command
call WRITE_COMMAND_OP
mov cx, 1
mov dx, commCount
call WRITE_OUTPUT
jmp short WC_END
NO_COUNT:
push ax ; save and write command
call WRITE_COMMAND_OP
pop ax
cmp al, 4
jl short WC_END
je short COMMAND_SQUROPEN
cmp al, 6
jl short COMMAND_POINT
je short COMMAND_COMMA
jg short COMMAND_SQURCLOSE
WC_END:
mov byte [commCount], 1
mov byte [prevCommand], 0FFh
ret
COMMAND_SQUROPEN:
inc byte [squrBrack] ; for syntax-check
pop bx ; save return address for WRITE_COMMAND
push word [outPos]
push bx
jmp short WC_END
COMMAND_POINT:
mov ax, 1Bh
call WRITE_DIFF
jmp short WC_END
COMMAND_COMMA:
mov ax, 0Fh
call WRITE_DIFF
jmp short WC_END
WRITE_DIFF:
; ax = offset to jump to
mov cx, 2
sub ax, [outPos]
sub ax, cx
mov word [addressBuf], ax
mov dx, addressBuf
call WRITE_OUTPUT ; write offset for jmp
ret
WRITE_COMMAND_OP:
; al = number of command to write (0 to 11)
mov si, opPlusInc
;xor bh, bh
FIND_OPCODE:
dec al ; cmp al, 0
js short WRITE_OPCODE
mov bl, byte [si]
add si, bx
inc si
jmp short FIND_OPCODE
WRITE_OPCODE:
; si = address of array of opcodes, first byte must be size
;xor cx, cx
mov cl, byte [si]
mov dx, si
inc dx
WRITE_OUTPUT:
; cx = number of bytes to write
; dx = address of bytes to write
mov ah, 40h
mov bx, [fileOut]
int 21h
jc ERROR_FILE
add word [outPos], ax
ret