Brainfuck Hello World实际上如何工作?

有人把这件事发给我,并声称这是一个在Brainfuck你好的世界(我希望如此...)

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

我知道它的基础知识,它通过移动指针并递增和递减东西来工作。

但我仍然想知道,它是如何工作的? 它如何在屏幕上首先打印任何内容? 它如何编码文本? 我根本听不懂......


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表。 例如,十进制代码!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会执行print操作:

一个

因为ASCII中a十进制代码是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。


维基百科有一个注释版本的代码。

+++++ +++++             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。

维基百科的文章也进一步深入。

第一行通过从0递增10次来初始化a[0] = 10来自第2行的循环有效地设置了数组的初始值: a[1] = 70 (接近72,字符' H'), a[2] = 100 (接近101或'e'), a[3] = 30 (接近32,空格代码)和a[4] = 10 (换行符)。 该循环通过每次通过循环时分别向单元a[1]a[2]a[3]a[4]添加7,10,3和1来工作 - 每个单元总共增加10个给出a[1]=70等)。 循环结束后, a[0]为零。 >++. 然后将指针移动到a[1] (其中包含70),将其加2(生成72,这是大写字母H的ASCII字符代码),并将其输出。

下一行将数组指针移动到a[2]并将其加1,产生101,小写的'e',然后输出。

由于'l'恰好是'e'之后的第七个字母,为了输出'll',另外七个被添加( +++++++ )到a[2]并且结果被输出两次。

'o'是'l'后面的第三个字母,所以a[2]再增加三次并输出结果。

程序的其余部分以相同的方式继续。 对于空格和大写字母,根据需要选择不同的数组单元格并递增或递减。


要回答它如何知道要打印什么的问题,我已经将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)
链接地址: http://www.djcxy.com/p/67869.html

上一篇: How does the Brainfuck Hello World actually work?

下一篇: Turing completeness of lambda calculus?