spe*_*der 111 esoteric-languages brainfuck
有人把它寄给我,并声称这是Brainfuck的一个问候世界(我希望如此......)
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
Run Code Online (Sandbox Code Playgroud)
通过移动指针并递增和递减东西,我知道它的基本功能......
但我仍然想知道它是如何运作的?它首先如何在屏幕上打印任何内容?它如何编码文本?我根本不明白......
Sco*_*ony 236
要了解Brainfuck,您必须想象0每个单元初始化的无限数组.
...[0][0][0][0][0]...
Run Code Online (Sandbox Code Playgroud)
当brainfuck程序启动时,它指向任何单元格.
...[0][0][*0*][0][0]...
Run Code Online (Sandbox Code Playgroud)
如果向右>移动指针,则将指针从单元格X移动到单元格X + 1
...[0][0][0][*0*][0]...
Run Code Online (Sandbox Code Playgroud)
如果你增加单元格值,+你得到:
...[0][0][0][*1*][0]...
Run Code Online (Sandbox Code Playgroud)
如果再次增加单元格值,+则会得到:
...[0][0][0][*2*][0]...
Run Code Online (Sandbox Code Playgroud)
如果您降低单元格值,-您会得到:
...[0][0][0][*1*][0]...
Run Code Online (Sandbox Code Playgroud)
如果向左<移动指针,则将指针从单元格X移动到单元格X-1
...[0][0][*0*][1][0]...
Run Code Online (Sandbox Code Playgroud)
要阅读角色,请使用逗号,.它的作用是:从标准输入读取字符并将其十进制ASCII码写入实际单元格.
看看ASCII表.例如,十进制代码!是33,a而是97.
好吧,让我们想象你的BF程序内存如下:
...[0][0][*0*][0][0]...
Run Code Online (Sandbox Code Playgroud)
假设标准输入代表a,如果你使用逗号,运算符,BF做的是读取a十进制ASCII代码97到内存:
...[0][0][*97*][0][0]...
Run Code Online (Sandbox Code Playgroud)
你通常想要那样思考,但真相有点复杂.事实是BF不读取字符而是读取字节(无论该字节是什么).让我举个例子:
在linux中
$ printf ?
Run Code Online (Sandbox Code Playgroud)
打印:
?
Run Code Online (Sandbox Code Playgroud)
这是特定的抛光特征.此字符不是由ASCII编码编码的.在这种情况下,它是UTF-8编码,因此它曾经在计算机内存中占用多个字节.我们可以通过制作十六进制转储来证明它:
$ printf ? | hd
Run Code Online (Sandbox Code Playgroud)
这表现了:
00000000 c5 82 |..|
Run Code Online (Sandbox Code Playgroud)
零被抵消.82是第一个并且c5是第二个字节代表?(按顺序我们将读取它们).|..|是图形表示,在这种情况下是不可能的.
好吧,如果你?作为输入传递给读取单字节的BF程序,程序存储器将如下所示:
...[0][0][*197*][0][0]...
Run Code Online (Sandbox Code Playgroud)
为什么197?那么197十进制为c5十六进制.似乎很熟悉?当然.这是第一个字节?!
要打印字符,请使用dot .它的作用是:假设我们将实际单元格值视为十进制ASCII代码,将相应字符打印到标准输出.
好吧,让我们想象你的BF程序内存如下:
...[0][0][*97*][0][0]...
Run Code Online (Sandbox Code Playgroud)
如果你现在使用点(.)运算符,BF会做什么打印:
一个
因为aASCII中的十进制代码是97.
所以例如像这样的BF程序(97加2点):
++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++ ..
将它指向的单元格值增加到97并将其打印出来2次.
AA
BF循环由循环开始[和循环结束组成].您可以认为它就像在C/C++中,条件是实际的单元格值.
看看下面的BF程序:
++[]
Run Code Online (Sandbox Code Playgroud)
++ 两次增加实际单元格值:
...[0][0][*2*][0][0]...
Run Code Online (Sandbox Code Playgroud)
而[]像while(2) {},所以它的无限循环.
假设我们不希望这个循环是无限的.我们可以这样做:
++[-]
Run Code Online (Sandbox Code Playgroud)
因此每次循环循环时,它会减少实际的单元格值.一旦实际单元格值为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)
Run Code Online (Sandbox Code Playgroud)
让我们再看一下有限循环的另一个例子:
++[>]
Run Code Online (Sandbox Code Playgroud)
这个例子表明,我们没有在循环开始的单元格上完成循环:
...[0][0][*2*][0][0]... loop starts
...[0][0][2][*0*][0]... after first iteration (loop ends)
Run Code Online (Sandbox Code Playgroud)
但是,最好结束我们开始的地方.为什么?因为如果循环结束它开始的另一个单元格,我们就不能假设单元格指针在哪里.说实话,这种做法使脑力劳动减少了脑力.
ken*_*ken 50
维基百科有一个评论版的代码.
+++++ +++++ 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'
Run Code Online (Sandbox Code Playgroud)
要回答您的问题,,和.字符用于I/O. 文字是ASCII.
在维基百科的文章接着在一些更深入,以及.
第一行
a[0] = 10通过简单地从0递增十次来初始化.第2行的循环有效地设置了数组的初始值:(a[1] = 70接近72,字符'H'的ASCII代码),a[2] = 100(接近101或'e' ),a[3] = 30(接近32,空间代码)和a[4] = 10(换行符).循环的工作原理是7,10,3,和1,细胞增加a[1],a[2],a[3]和a[4]分别各一次通过循环-在总(给予10添加用于每个小区a[1]=70等).循环结束后,a[0]为零.>++.然后将指针移动到a[1],它保持70,向它添加两个(产生72,这是大写H的ASCII字符代码),并输出它.下一行将数组指针移动到
a[2]并向其添加一个,产生101,小写的"e",然后输出.由于'l'恰好是'e'之后的第七个字母,输出'll'时,另外七个被添加(
+++++++),a[2]结果输出两次.'o'是'l'之后的第三个字母,因此
a[2]再增加三次并输出结果.程序的其余部分以相同的方式继续.对于空格和大写字母,选择不同的阵列单元并根据需要递增或递减.
小智 8
为了回答它如何知道打印内容的问题,我在打印发生的代码右侧添加了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)
Run Code Online (Sandbox Code Playgroud)
Brainfuck
和它的名字一样.它只使用8个字符> [ . ] , - +,这使它成为学习中最快的编程语言,但却难以实现和理解.
....并且最终让你最终得到你的大脑.
它将值存储在数组中:[72] [101] [108] [111]
let,最初指针指向数组的单元格1:
> 将指针向右移动1
< 将指针向左移动1
+ 将单元格的值增加1
- 将元素的值增加1
. 当前单元格的打印值.
, 将输入输入当前单元格.
[ ] 循环,+++ [ - ]计数器3计数bcz它前面有3'+', - 减少计数变量1值.
存储在单元格中的值是ascii值:
所以参考上面的数组:[72] [101] [108] [108] [111]如果你匹配ascii值,你会发现它是Hello writtern
恭喜!你已经学会了BF的语法
--- 更多 ---
让我们制作我们的第一个程序,即Hello World,之后您就可以用这种语言编写您的名字了.
+++++ +++++[> +++++ ++ >+++++ +++++ >+++ >+ <<<-]>++.>+.+++++ ++..+++.++.+++++ +++++ +++++.>.+++.----- -.----- ---.>+.>.
Run Code Online (Sandbox Code Playgroud)
分成几块:
+++++ +++++[> +++++ ++
>+++++ +++++
>+++
>+
<<<-]
Run Code Online (Sandbox Code Playgroud)
制作一个包含4个单元格的数组(数量为>)并设置一个10的计数器,如: - psuedo code--
array =[7,10,3,1]
i=10
while i>0:
element +=element
i-=1
Run Code Online (Sandbox Code Playgroud)
因为计数器值存储在单元格0中并且>移动到单元格1更新其值+ 7>移动到单元格2将10增加到其先前值,依此类推....
<<< 返回单元格0并将其值减1
因此在循环完成后我们有数组:[70,100,30,10]
>++.
Run Code Online (Sandbox Code Playgroud)
移动到第一个元素并将其值增加2(两个'+'),然后使用该ascii值打印('.')字符.即例如在python中:chr(70 + 2)#打印'H'
>+.
Run Code Online (Sandbox Code Playgroud)
移动到第二个单元格增量1到它的值100 + 1并打印('.')它的值,即chr(101)chr(101)#prints'e'现在没有>或<in next piece,所以它取现值最新元素和增量只有它
+++++ ++..
Run Code Online (Sandbox Code Playgroud)
最新元素= 101因此,101 + 7并打印两次(因为有两个'..')chr(108)#prints l两次可以用作
for i in array:
for j in range(i.count(‘.’)):
print_value
Run Code Online (Sandbox Code Playgroud)
--- 它在哪里使用?---
它只是一种用来挑战程序员的笑话语言,并没有在任何地方使用.
小智 5
所有答案都很详尽,但缺少一个微小的细节:打印。在构建 Brainfuck 翻译器时,您还需要考虑角色.,这实际上就是 Brainfuck 中打印语句的样子。所以你的大脑翻译器应该做的是,每当它遇到一个.字符时,它就会打印当前指向的字节。
例子:
假设你有 --> char *ptr = [0] [0] [0] [97] [0]...如果这是一个 Brainfuck 语句: >>>.你的指针应该移动 3 个空格到右侧着陆点:[97],所以现在*ptr = 97,在你的翻译器遇到 a 之后.,它应该调用
write(1, ptr, 1)
Run Code Online (Sandbox Code Playgroud)
或任何等效的打印语句来打印当前指向的字节,其值为97,然后该字母a将被打印在std_output.