2013-05-30 36 views
85

有人發這個給我,並聲稱這是Brainfuck一個Hello World(我希望如此......)Brainfuck Hello World實際上是如何工作的?

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>. 

我知道的基本知識,它的工作原理是移動一個指針和增量和遞減的東西.. 。

但是我仍然想知道,它是如何工作的?它如何在屏幕上首先打印任何內容?它如何編碼文本?我完全不明白...

+16

一定很難保持用這種語言編寫的應用程序。 –

+11

@ ring0:不,這是一種只寫語言。 – LetMeSOThat4U

+0

它有什麼實際用途? –

回答

166

1.基礎

要了解Brainfuck你必須想象每個0初始化細胞的無限陣列。

...[0][0][0][0][0]... 

當brainfuck程序啓動時,它指向任何單元格。

...[0][0][*0*][0][0]... 

如果移動指針向右>你是從小區X移動指針到單元X + 1

...[0][0][0][*0*][0]... 

如果您增加單元格值+你:

...[0][0][0][*1*][0]... 

如果您再次提高單元格價格+即可獲得:

...[0][0][0][*2*][0]... 

如果減少細胞值-你:

...[0][0][0][*1*][0]... 

如果移動指針離開<你是從小區X移動指針小區X-1

...[0][0][*0*][1][0]... 

2.輸入

要閱讀字符,請使用逗號,。它的作用是:從標準輸入讀取字符並將其十進制ASCII碼寫入實際單元。

看看ASCII table。例如,!的十進制代碼是33,而a97

好吧,讓我們來想象你的BF程序存儲器的樣子:

...[0][0][*0*][0][0]... 

假設標準輸入代表a,如果使用逗號,運營商,什麼BF不讀a進制ASCII碼97內存:

...[0][0][*97*][0][0]... 

你一般都想這樣想,但事實有點複雜。事實是,BF不會讀取字符,而是讀取一個字節(無論該字節是什麼)。讓我告訴你例子:

在linux下

$ printf ł 

打印:

ł 

這是具體的拋光特性。該字符不是由ASCII編碼編碼的。在這種情況下,它是UTF-8編碼,所以它在計算機內存中佔用了多個字節。我們可以做一個十六進制轉儲證明這一點:

$ printf ł | hd 

表示:

00000000 c5 82            |..| 

零被抵消。82是第一個,並且c5是代表ł的第二個字節(爲了我們將讀取它們)。 |..|是在這種情況下不可能的圖形表示。

好吧,如果你通過ł輸入到你的BF程序,讀取單字節,程序存儲器將看起來像:

...[0][0][*197*][0][0]... 

爲什麼197?那麼197十進制是c5十六進制。似乎很熟悉?當然。它是ł的第一個字節!

3.輸出

要打印字符使用點.它所做的是:假設我們像對待進制ASCII代碼的實際單元格的值,打印對應的字符到標準輸出。

好吧,讓我們來想象你的BF程序存儲器的樣子:(。)

...[0][0][*97*][0][0]... 

如果你現在使用點操作,所做的BF是打印:

一個

因爲a ASCII中的十進制代碼是97

因此,例如BF程序是這樣的(97個加號2點):

++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++ ..

將增加它指向的單元格的值爲97並將其打印出來2次。

AA

4.循環

在BF循環由循環的開始和[循環結束]。你可以認爲它就像在C/C++中那樣,條件是實際的單元格值。

看看BF程序如下:

++[] 

++增量實際單元格值的兩倍:

...[0][0][*2*][0][0]... 

而且[]就像while(2) {},所以它的無限循環。

假設我們不希望這個循環是無限的。例如我們可以這樣做:

++[-] 

所以每次循環循環它都會減少實際的單元格值。一旦實際單元格的值是0循環結束:

...[0][0][*2*][0][0]...  loop starts 
...[0][0][*1*][0][0]...  after first iteration 
...[0][0][*0*][0][0]...  after second iteration (loop ends) 

讓我們考慮有限循環的另一個例子:

++[>] 

這個例子說明,我們沒有在這個循環開始對細胞完成循環:

...[0][0][*2*][0][0]...  loop starts 
...[0][0][2][*0*][0]...  after first iteration (loop ends) 

但是,最好結束我們開始的地方。爲什麼?因爲如果循環結束了它啓動的另一個單元格,我們不能假定單元格指針將在哪裏。說實話,這種做法使得brainfuck減少brainfuck。

+2

酷,現在我明白了:) – speeder

+0

'''''''''''''? :( –

+0

一般來說,我的目標只是解釋思想,但你是對的,我很快就會提高我的答案。 – Scony

42

Wikipedia有一個註釋版本的代碼。

+++++ +++++    initialize counter (cell #0) to 10 
[      use loop to set the next four cells to 70/100/30/10 
    > +++++ ++    add 7 to cell #1 
    > +++++ +++++   add 10 to cell #2 
    > +++     add 3 to cell #3 
    > +      add 1 to cell #4 
    <<<< -     decrement counter (cell #0) 
]     
> ++ .     print 'H' 
> + .     print 'e' 
+++++ ++ .    print 'l' 
.      print 'l' 
+++ .     print 'o' 
> ++ .     print ' ' 
<< +++++ +++++ +++++ . print 'W' 
> .      print 'o' 
+++ .     print 'r' 
----- - .    print 'l' 
----- --- .    print 'd' 
> + .     print '!' 
> .      print '\n' 

回答您的問題時,,.字符用於I/O。文本是ASCII。

Wikipedia這篇文章進一步深入。 a[1] = 70(接近72,對於字符 1 H ASCII碼:

第一行通過簡單地從0從線2上的環有效地設置初始值 陣列遞增十倍 初始化a[0] = 10 '),a[2] = 100(接近於101或'e'),a[3] = 30(接近於32,代碼爲空格的 )和a[4] = 10(換行符)。循環的工作原理是將圖7, 10,圖3和1,細胞a[1]a[2]a[3]a[4]分別各 一次通過循環 - 在總(給出 a[1]=70等)10添加用於每個小區。循環結束後,a[0]爲零。 >++.然後 將指針移動到a[1](其中包含70),將它加上兩個(產生 72,這是大寫字母H的ASCII字符代碼),並輸出它。

下一行將數組指針移動到a[2],並將其加1, 產生101,一個小寫的'e',然後輸出。

作爲「L」發生 是「E」後的第七個字母,以輸出「L-L」的另一7是 加入(+++++++)至a[2],結果是輸出兩次。

'o'是'l'後的第三個字母 ,所以a[2]增加了三次, 輸出結果。

程序的其餘部分以相同的方式繼續。 對於空格和大寫字母,選擇不同的數組單元格 並根據需要遞增或遞減。

+0

但是爲什麼它打印?或者如何?評論向我解釋了該行的意圖,現在它做了什麼。 – speeder

+6

因爲編譯器知道''''和'.'被用於I/O,所以可以打印,就像使用'putchar'打印C文件一樣。它是編譯器處理的實現細節。 – ken

+0

還因爲它將所需的單元格設置爲「Hello World」中的ASCII字符的整數值 – slugonamission

1

所有的答案都很全面,但他們缺少一個小細節:打印。 在建立你的腦袋翻譯器時,你也會考慮字符.,這實際上是一個打印語句在brainfuck中的樣子。所以你的腦子翻譯器應該做的是,只要遇到.字符,就會打印當前指向的字節。

例子:

假設你有 - >char *ptr = [0] [0] [0] [97] [0] ...... 如果這是一個brainfuck聲明:>>>.你的指針應該在移動3個格,以正確的目標:[97],所以現在*ptr = 97,後這樣做,您的翻譯遇到.,它應該然後調用

write(1, ptr, 1) 

或任何同等打印語句來打印當前尖字節,其值爲和字母a將被打印在std_output上。

4

要回答它是如何知道打印什麼的問題,我加ASCII值的計算代碼,其中印刷情況的權利:

> just means move to the next cell 
< just means move to the previous cell 
+ and - are used for increment and decrement respectively. The value of the cell is updated when the increment/decrement happens 

+++++ +++++    initialize counter (cell #0) to 10 

[      use loop to set the next four cells to 70/100/30/10 

> +++++ ++    add 7 to cell #1 

> +++++ +++++   add 10 to cell #2 

> +++     add 3 to cell #3 

> +      add 1 to cell #4 

<<<< -     decrement counter (cell #0) 

]    

> ++ .     print 'H' (ascii: 70+2 = 72) //70 is value in current cell. The two +s increment the value of the current cell by 2 

> + .     print 'e' (ascii: 100+1 = 101) 

+++++ ++ .    print 'l' (ascii: 101+7 = 108) 

.      print 'l' dot prints same thing again 

+++ .     print 'o' (ascii: 108+3 = 111) 

> ++ .     print ' ' (ascii: 30+2 = 32) 

<< +++++ +++++ +++++ . print 'W' (ascii: 72+15 = 87) 

> .      print 'o' (ascii: 111) 

+++ .     print 'r' (ascii: 111+3 = 114) 

----- - .    print 'l' (ascii: 114-6 = 108) 

----- --- .    print 'd' (ascii: 108-8 = 100) 

> + .     print '!' (ascii: 32+1 = 33) 

> .      print '\n'(ascii: 10) 
1

Brainfuck 同它的名字。 它只使用8個字符> [ . ] , - +這使得它最快編程語言學習最難實施和理解。 ...。讓你終於結束了你的大腦。

它存儲在數組的值:[72] [101] [108] [111]

讓,最初指針指向單元陣列的1:

  1. >移動指針到右1個

  2. <移動指針到左通過1

  3. +增量值o ˚F細胞通過1

  4. -增量元素的值由當前小區的1

  5. .打印值。

  6. ,將輸入輸入到當前單元。

  7. [ ] loop +++ [ - ]計數3次計數bcz它前面有3'+',以及 - 計數變量減1計數。

存儲在單元中的值是ASCII值:

所以參考以上數組:[72] [101] [108] [108] [111] 如果匹配的ASCII值你」你會發現它是你好書寫器

恭喜!你已經學會BF

的語法

--- 更多的東西 ---

讓我們使我們的第一個程序,即的Hello World,之後,你能夠在此寫下你的名字語言。

+++++ +++++[> +++++ ++ >+++++ +++++ >+++ >+ <<<-]>++.>+.+++++ ++..+++.++.+++++ +++++ +++++.>.+++.----- -.----- ---.>+.>. 

破成碎片:

+++++ +++++[> +++++ ++ 
        >+++++ +++++ 
        >+++ 
        >+ 
        <<<-] 

使4個單元的陣列(數>),並設置爲10類似的計數器: --psuedo代碼 -

array =[7,10,3,1] 
i=10 
while i>0: 
element +=element 
i-=1 

因爲計數器值存儲在單元格0中並且>移動到單元格1時將其值更新爲+ 7>移動到單元格2將10遞增到其之前的值,等等......。

<<<返回到小區0和循環完成之後,因此減1

其值,我們有數組:[70,100,30,10]

>++. 

移動到第一元件,並通過增加其值2(兩個'+'),然後用該ascii值打印('。')字符。一世。e計算例如在python: CHR(70 + 2)#打印 'H'

>+. 

移動到第二小區增量1至其值100 + 1,並打印( '')其值即CHR(101 ) CHR(101)#prints「E」 現在存在下一塊無>或<所以需要最新元件和增量的現值到它僅

+++++ ++.. 

最新元件= 101因此,101+ 7並打印兩次(因爲有兩個'..')chr(108)#prints l兩次 可用作

for i in array: 
    for j in range(i.count(‘.’)): 
      print_value 

--- 它在哪裏使用? ---

這只是一種用來挑戰程序員的笑話語言,幾乎沒有用在任何地方。