171 byte 1
Wooohoooo! Mất nửa ngày, nhưng thật vui ...
Vì vậy, đây là. Tôi nghĩ rằng nó phù hợp với thông số kỹ thuật (bao quanh con trỏ ô, tiếng vang của các ký tự đầu vào, đọc char bằng char, echo của ký tự đầu vào, ...), và nó dường như thực sự hoạt động (tốt, tôi đã không thử nhiều chương trình , nhưng với sự đơn giản của ngôn ngữ, phạm vi bảo hiểm không tệ đến thế, tôi nghĩ vậy).
Hạn chế
Một điều quan trọng: nếu chương trình brainfuck của bạn có chứa các ký tự khác ngoài 8 hướng dẫn brainfuck hoặc nếu []
không được cân bằng tốt, nó sẽ sụp đổ với bạn, mouhahahaha!
Ngoài ra, chương trình brainfuck không thể vượt quá 512 byte (một sector). Nhưng điều này có vẻ phù hợp vì bạn nói "Brainfuck thực thi được đặt tại khu vực đĩa thứ hai" .
Chi tiết cuối cùng: Tôi đã không khởi tạo rõ ràng các ô về không. Qemu dường như làm điều đó cho tôi và tôi đang dựa vào điều này, nhưng tôi không biết liệu một BIOS thực sự trên một máy tính thực sự sẽ làm điều đó hay không (dù sao thì việc khởi tạo sẽ chỉ mất thêm vài byte).
Mật mã
(dựa trên mẫu của bạn và nhân tiện, cảm ơn vì điều này, tôi sẽ không bao giờ thử nếu không có nó):
[BITS 16]
[ORG 0x7C00]
%define cellcount 30000 ; you can't actually increase this value much beyond this point...
; first sector:
boot:
; initialize segment registers
xor ax, ax
mov ss, ax
mov ds, ax
mov es, ax
jmp 0x0000:$+5
; initialize stack
mov sp, 0x7bfe
; load brainfuck code into 0x8000
; no error checking is used
mov ah, 2 ; read
mov al, 1 ; one sector
mov ch, 0 ; cylinder & 0xff
mov cl, 2 ; sector | ((cylinder >> 2) & 0xc0)
mov dh, 0 ; head
; dl is already the drive number
mov bx, 0x8000 ; read buffer (es:bx)
int 0x13 ; read sectors
; initialize SI (instruction pointer)
mov si, bx ; 0x8000
; initialize DI (data pointer)
mov bh, 0x82
mov di, bx ; 0x8200
decode:
lodsb ; fetch brainfuck instruction character
.theend:
test al, al ; endless loop on 0x00
jz .theend
and ax, 0x0013 ; otherwise, bit shuffling to get opcode id
shl ax, 4
shl al, 2
shr ax, 1
add ax, getchar ; and compute instruction implementation address
jmp ax
align 32, db 0
getchar:
xor ah, ah
int 0x16
cmp al, 13
jne .normal
mov al, 10 ; "enter" key translated to newline
.normal:
mov byte [di], al
push di
jmp echochar
align 32, db 0
decrementdata:
dec byte [di]
jmp decode
align 32, db 0
putchar:
push di
mov al, byte [di]
echochar:
mov ah, 0x0E
xor bx, bx
cmp al, 10 ; newline needs additional carriage return
jne .normal
mov al, 13
int 0x10
mov al, 10
.normal:
int 0x10
pop di
jmp decode
align 32, db 0
incrementdata:
inc byte [di]
jmp decode
align 32, db 0
decrementptr:
dec di
cmp di, 0x8200 ; pointer wraparound check (really, was that necessary?)
jge decode
add di, cellcount
jmp decode
align 32, db 0
jumpback:
pop si
jmp jumpforward
align 32, db 0
incrementptr:
inc di
cmp di, 0x8200+cellcount ; pointer wraparound check
jl decode
sub di, cellcount
jmp decode
align 32, db 0
jumpforward:
cmp byte [di], 0
jz .skip
push si
jmp decode
.skip:
xor bx, bx ; bx contains the count of [ ] imbrication
.loop:
lodsb
cmp al, '['
je .inc
cmp al, ']'
jne .loop
test bx, bx
jz decode
dec bx
jmp .loop
.inc:
inc bx
jmp .loop
; fill sector
times (0x1FE)-($-$$) db 0
; boot signature
db 0x55, 0xAA
; second sector contains the actual brainfuck program
; currently: "Hello world" followed by a stdin->stdout cat loop
db '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.,[.,]'
times 0x400-($-$$) db 0
Thủ thuật được sử dụng
Ok, tôi đã lừa dối một chút. Vì bạn đã nói "là một bộ tải khởi động, kích thước của chương trình được tính bằng các byte khác không trong mã được biên dịch" , tôi đã làm cho mã nhỏ hơn bằng cách cho phép "lỗ hổng" giữa việc thực hiện tám mã não. Bằng cách này, tôi không cần một chuỗi các bài kiểm tra lớn, bảng nhảy hoặc bất cứ điều gì: Tôi chỉ cần nhảy đến "opcode id" (từ 0 đến 8) nhân với 32 để thực hiện hướng dẫn brainfuck (đáng lưu ý rằng điều đó có nghĩa là việc thực hiện các hướng dẫn không thể mất hơn 32 byte).
Hơn nữa, để có được "opcode id" này từ nhân vật chương trình brainfuck, tôi nhận thấy chỉ cần một chút xáo trộn là cần thiết. Thật vậy, nếu chúng ta chỉ xem xét các bit 0, 1 và 4 của ký tự opcode, chúng ta sẽ có 8 kết hợp duy nhất:
X XX
00101100 0x2C , Accept one byte of input, storing its value in the byte at the pointer.
00101101 0x2D - Decrement (decrease by one) the byte at the pointer.
00101110 0x2E . Output the value of the byte at the pointer.
00101011 0x2B + Increment (increase by one) the byte at the pointer.
00111100 0x3C < Decrement the pointer (to point to the next cell to the left).
01011101 0x5D ] Jump back after the corresp [ if data at pointer is nonzero.
00111110 0x3E > Increment the pointer (to point to the next cell to the right).
01011011 0x5B [ Jump forward after the corresp ] if data at pointer is zero.
Và thật may mắn cho tôi, thực sự có một opcode yêu cầu hơn 32 byte để thực hiện, nhưng đó là cái cuối cùng (nhảy về phía trước [
). Khi có nhiều phòng sau, mọi thứ đều ổn.
Một mẹo khác: Tôi không biết làm thế nào một trình thông dịch Brainfuck điển hình hoạt động, nhưng, để làm cho mọi thứ nhỏ hơn nhiều, tôi đã không thực sự thực hiện ]
như là "Quay trở lại sau tương ứng [
nếu dữ liệu tại con trỏ là khác không" . Thay vào đó, tôi luôn quay trở lại tương ứng [
, và từ đây, áp dụng lại cách [
thực hiện điển hình (mà sau đó, cuối cùng, sẽ tiếp tục sau khi ]
một lần nữa nếu cần). Đối với điều này, mỗi lần tôi trang bị a [
, tôi đặt "con trỏ lệnh Brainfuck" hiện tại lên ngăn xếp trước khi thực hiện các hướng dẫn bên trong và khi tôi gặp phải một]
, Tôi bật lại con trỏ chỉ dẫn. Khá nhiều như thể đó là một cuộc gọi đến một chức năng. Do đó, về mặt lý thuyết, bạn có thể vượt qua ngăn xếp bằng cách tạo ra nhiều vòng lặp được định nghĩa, nhưng không phải với giới hạn 512 byte hiện tại của mã brainfuck.
1. Bao gồm các byte không là một phần của chính mã, nhưng không bao gồm các byte là một phần của một số phần đệm
Input must be red
Tôi khá chắc chắn rằng hầu hết các bộ tải khởi động không hỗ trợ màu sắc.