這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
brainfuck 是極為簡化esoteric 程式設計語言,或許可以翻作蛋疼程式設計語言,僅有八條指令,如果用這玩意搞項目,應該比彙編編程還蛋疼,不過據說是圖靈完全。它的hello world 是這樣的:
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
整個代碼都是由+,-,>, <, . , [, ], , 組成。
Character Meaning
> 增加資料指標 (使其指向當前右邊記憶體單元).
< 減少資料指標(使其指向當前左邊記憶體單元).
+ 對當前記憶體單元加 1
- 對當前記憶體單元減 1
. 輸出當記憶體單元
, 接受一個位元組的輸入,將其放到當前資料指標指向的記憶體單元
[ 如果當前資料指標指向的單元,值為非0, 進入迴圈,執行緊靠 [ 後面的指令;否則,向前跳轉到與此 [ 匹配的 ] 之後開始執行
] 如果當前資料指標指向的單元,值為非0,向後跳轉,回到與此 ] 匹配的 [ 後面執行, 否則,正常流程,繼續向下執行
brainfuck 命令 c語言等價操作
(Program Start) char array[infinitely large size] = {0};
char *ptr=array;
> ++ptr;
< --ptr;
+ ++*ptr;
- --*ptr;
. putchar(*ptr);
, *ptr=getchar();
[ while (*ptr) {
] }
package mainimport ("fmt""io/ioutil""os")//表達brainfuck使用的機器模型,連續位元組記憶體塊type tape struct {mem []bytepos int}func TapeNew() *tape {t := new(tape)t.mem = make([]byte, 4096)return t}//.操作, putchar(*ptr)func (t *tape) get() byte { return t.mem[t.pos] }//,操作, *ptr = getchar()func (t *tape) set(val byte) { t.mem[t.pos] = val }//+操作, ++*ptrfunc (t *tape) inc() { t.mem[t.pos]++ }//-操作, --*ptrfunc (t *tape) dec() { t.mem[t.pos]-- }//>操作, ++ptrfunc (t *tape) forward() {t.pos++if len(t.mem) <= t.pos {t.mem = append(t.mem, 0)}}//<操作,--ptrfunc (t *tape) backward() { t.pos-- }func interpret(prog string, whilemap map[int]int) {pc := 0tape := TapeNew()var tmp bytefor pc < len(prog) {switch prog[pc] {case '>':tape.forward()case '<':tape.backward()case '+':tape.inc()case '-':tape.dec()case '.':c := tape.get()fmt.Printf("%c", c)case ',':fmt.Scanf("%c", &tmp)tape.set(tmp)case '[':if tape.get() == 0 {pc = whilemap[pc]}case ']':if tape.get() != 0 {pc = whilemap[pc]}}pc++}}func parse(prog string) (string, map[int]int) {parsed := make([]byte, 0)pcstack := make([]int, 0)//記錄[,對應的],索引(指令)位置whilemap := make(map[int]int, 128)pc := 0for _, char := range prog {//fmt.Printf("got char: %c\n", char)switch char {case '>', '<', '+', '-', '.', ',', '[', ']':parsed = append(parsed, byte(char))if char == '[' {pcstack = append(pcstack, pc)} else if char == ']' {last := len(pcstack) - 1left := pcstack[last]pcstack = pcstack[:last]right := pcwhilemap[right] = leftwhilemap[left] = right}pc++}}return string(parsed), whilemap}func main() {if len(os.Args) < 2 {fmt.Printf("Usage: %s <brainfuck source file>\n", os.Args[0])os.Exit(1)}c, err := ioutil.ReadFile(os.Args[1])if err != nil {fmt.Printf("read brainfuck file failed!\n")os.Exit(2)}interpret(parse(string(c)))}
hello.b:
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++../brainfuck hello.bHello World!add.b:>> + [- >,>+< ----- ----- ----- ----- ; checking with ascii 43 ie plus symbol ----- ----- ----- ----- --- [ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++ < ] >> ] ; first input is over and terminated by a 'plus' symbol <->>>>>+ [- >,>+< ----- ----- ----- ----- ; checking with ascii 61 ie = symbol ----- ----- ----- ----- ----- ----- ----- ------ [ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ ++++++ < ] >> ] ; second input is over and terminated by an = symbol ; now the array looks like 0 0 0 49 0 50 0 0 0 0 0 0 0 0 49 0 53 0 0 1 0 ; for an input 12'plus'15= <<<< [<+<] ; filled with 1's in between + [<+>-<<[>-]>] ; This is a special loop to traverse LEFT through indefinite no of 0s ; Lets call it left traverse << [<+<] >[>]< ; now the array looks like ; 0 0 1 49 1 50 0 0 0 0 0 0 0 1 49 1 53 0 0 1 for eg:12plus15 [ [->+> + [>+<->>[<-]<] ; Right traverse >>[>]<+ [<] + [<+>-<<[>-]>] ; Left traverse <<-< ] + [>+<->>[<-]<] >> [>] <<-<[<] + [<+>-<<[>-]>] <<-< ] ; now actual addition took place ; ie array is 00000000000000 98 0 103 0 0 1 + [>+<->>[<-]<] >> [ ----- ----- ----- ----- ----- ----- ----- ----- ----- --- >>] ; minus 48 to get the addition correct as we add 2 ascii numbers >-< ; well an undesired 1 was there 2 place after 103 right ? just to kill it ; now the array is 00000 00000 0000 50 0 55 ; now comes the biggest task Carry shifting << [<<] +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++ [>>] ; we added a 48 before all the digits in case there is an overall carry ; to make the size n plus 1 ; array : 00000 00000 00 48 0 50 0 55 << << [ [>>->[>]>+>>>> >>>+<<<< <<<<<[<]><<] >+[>]>- [-<<[<]>+[>]>] >>>>>+>>> +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++ < ; comparison loop: 0 1 0 a b 0 ; (q) (p) (num) (58) [->-[>]<<] ; comparison loop to check each digit with 58: greater means ; we need to minus 10 and add 1 to next significant digit <[- ; n greater than or equal to 58 (at p) <<<< <<< [<]+ > ----- ----- ; minus 10 to that digit <<+ ; plus 1 to next digit > [>] >>>>>> ] < [-< ; n less than 58 (at q) <<<<<< [<]+ [>] >>>>> ] ; at (q) >>>[-]>[-] <<<<< <<<<< [<]> << ] ; Its all over now : something like 0 48 0 52 0 66 ( ie 0 4 18 ) ; will turn into 0 48 0 53 0 56 (ie 0 5 8) >> ----- ----- ----- ----- ----- ----- ----- ----- ----- --- ; here we are just checking first digit is 48 or not ; its weird to print 0 ahead but it is defenitely needed ; if it is 49 ie 1 [ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++++ +++ . [-] ] >> [.>>] +++++ +++++ . ; to print nextline : ascii 10
./brainfuck add.b
1234+0001=
1235
fib.b:
>++++++++++>+>+[
[+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.>>[
[-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
[>+<-[>+<-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>>
]<<<
]
./brainfuck fib.b