1. Básico
Para entender o Brainfuck, você deve imaginar um conjunto infinito de células inicializadas por 0cada um.
...[0][0][0][0][0]...
Quando o programa Brainfuck é iniciado, ele aponta para qualquer célula.
...[0][0][*0*][0][0]...
Se você mover o ponteiro para a direita, >você está movendo o ponteiro da célula X para a célula X + 1
...[0][0][0][*0*][0]...
Se você aumentar o valor da célula, +obterá:
...[0][0][0][*1*][0]...
Se você aumentar o valor da célula novamente, +obterá:
...[0][0][0][*2*][0]...
Se você diminuir o valor da célula, -obterá:
...[0][0][0][*1*][0]...
Se você mover o ponteiro para a esquerda, <você está movendo o ponteiro da célula X para a célula X-1
...[0][0][*0*][1][0]...
2. Entrada
Para ler caracteres, você usa vírgula ,. O que ele faz é: Ler o caractere da entrada padrão e gravar seu código ASCII decimal na célula real.
Dê uma olhada na tabela ASCII . Por exemplo, código decimal de !is 33, while ais 97.
Bem, vamos imaginar que a memória do seu programa BF seja semelhante a:
...[0][0][*0*][0][0]...
Assumindo que a entrada padrão representa a, se você usar o ,operador vírgula , o que BF faz é ler o acódigo ASCII decimal 97para a memória:
...[0][0][*97*][0][0]...
Você geralmente quer pensar dessa maneira, mas a verdade é um pouco mais complexa. A verdade é que o BF não lê um caractere, mas um byte (seja ele qual for). Deixe-me mostrar um exemplo:
Em linux
$ printf ł
estampas:
ł
que é um caráter polonês específico. Este caractere não é codificado pela codificação ASCII. Nesse caso, é a codificação UTF-8, então costumava ocupar mais de um byte na memória do computador. Podemos provar isso fazendo um despejo hexadecimal:
$ printf ł | hd
que mostra:
00000000 c5 82 |..|
Zeros são compensados. 82é o primeiro e o c5segundo byte representando ł(para que possamos lê-los).|..|é a representação gráfica que não é possível neste caso.
Bem, se você passar łcomo entrada para o seu programa BF que lê byte único, a memória do programa será semelhante a:
...[0][0][*197*][0][0]...
Porque 197? Bem, 197decimal é c5hexadecimal. Parece familiar? Claro. É o primeiro byte de ł!
3. Saída
Para imprimir o caractere, você usa o ponto. .O que ele faz é: Assumindo que tratamos o valor real da célula como código ASCII decimal, imprime o caractere correspondente na saída padrão.
Bem, vamos imaginar que a memória do seu programa BF seja semelhante a:
...[0][0][*97*][0][0]...
Se você usar o operador ponto (.) Agora, o que BF faz é imprimir:
uma
Porque o acódigo decimal em ASCII é 97.
Então, por exemplo, programa BF como este (97 mais 2 pontos):
+++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++
Aumentará o valor da célula que aponta para até 97 e imprime 2 vezes.
aa
4. Loops
Em BF, o loop consiste no início [e no final do loop ]. Você pode pensar que é como em C / C ++, onde a condição é o valor real da célula.
Dê uma olhada no programa BF abaixo:
++[]
++ incrementa o valor real da célula duas vezes:
...[0][0][*2*][0][0]...
E []é assim while(2) {}, então é um loop infinito.
Digamos que não queremos que esse loop seja infinito. Podemos fazer por exemplo:
++[-]
Portanto, cada vez que um loop faz um loop, ele diminui o valor real da célula. Assim que o valor real da célula 0terminar o loop:
...[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)
Vamos considerar outro exemplo de loop finito:
++[>]
Este exemplo mostra que não devemos terminar o loop na célula em que o loop começou:
...[0][0][*2*][0][0]... loop starts
...[0][0][2][*0*][0]... after first iteration (loop ends)
No entanto, é uma boa prática terminar onde começamos. Por quê ? Porque se o loop termina em outra célula, ele começou, não podemos assumir onde o ponteiro da célula estará. Para ser honesto, essa prática torna a foda cerebral menos foda.