Para a pessoa jovem que cansou do brain rot e está em busca de coisas mais pesadas, talvez brainfuck seja a solução: uma linguagem esotérica que, com apenas 8 instruções, implementa uma Máquina de Turing completa. Isso significa que, com persistência e criatividade, a pessoa jovem pode implementar toda sorte de algoritmo!
A linguagem possui apenas 8 instruções:
| instrução | descrição |
|---|---|
| + | soma um na célula de memória atual; quando a célula está com 255, somar um volta para 0 (comportamento circular). |
| - | subtrai um na célula de memória atual; quando a célula está com 0, subtrair um volta para 255 (comportamento circular). |
| > | avança para a próxima célula de memória; quando a última célula está selecionada, avançar um volta para a célula 0 (comportamento circular). |
| < | recua para a célula de memória anterior; quando a primeira célula está selecionada, voltar um volta para a última célula (comportamento circular). |
| . | escreve o conteúdo da célula de memória atual na saída (output), em formato hexa decimal. |
| , | lê um byte para a célula de memória atual da entrada (input), em formato hexadecimal. |
| [ | se a célula de memória atual não for zero, repete os comandos dentro do bloco que se encerra com ]. se for zero, pula para a instrução após o ] de fechamento do loop. loops aninhados são aceitos! |
| ] | encerra um bloco aberto por [. |
Com um conjunto pequeno de instruções, até que é fácil criar um interpretador para a linguagem, mas escrever programas já é outra história — não é a toa o nome brainfuck, rssss. Dá uma olhada no programa de exemplo, sem os comentários...
+++++
>+++++++
>------
>,
<<<.
>.
>.
>.
[
-
>++++++++++
[
-
.
]
<
.
]
Note que qualquer caráter diferente dos presentes na tabela de instruções devem ser ignorados pelo interpretador.
A máquina virtual do interpretador tem 8 bits, ou seja, cada célula de memória tem 8 bits de tamanho. A memória do simulador desta página tem 5000 células de memória, mas este valor pode ser alterado via argumento do construtor da classe.
O interpretador é uma máquina que precisa controlar 2 ponteiros: o de memória e o de instruções. O ponteiro de memória só pode ser afetado quando o interpretador executa instruções de deslocamento de células: '>' (avançar um endereço) e '<' (recuar um endereço). O ponteiro de instruções, por outro lado, é afetado após a execução de qualquer instrução:
Com isso em conta, o modelo de trabalho do interpretador pode ser esquematizado assim:
É importante observar que as instruções de entrada (',') e saída ('.') só trabalham com valores em hexadecimal com tamanho de até 1 byte.
O interpretador brainfuck desta página foi implementado como uma classe javascript, InterpretadorBrainfuck, no arquivo brainfuck.js. O construtor da classe apresenta os seguintes parâmetros:
| parâmetro | obrigatório | descrição |
|---|---|---|
| fonte | sim | Valor string com o código fonte em brainfuck. |
| tamanho_memoria | sim | Quantidade de células de memória. No simulador desta página, estou considerando 5000 bytes. |
| on_output | não | Evento para tratar a execução da instrução de saída. |
| on_input | não | Evento para tratar a execução da instrução de entrada. No simulador desta página, o botão "entrar" é habilitado, para permitir ao usuário entrar com um byte. |
Para reduzir o tamanho do programa executado, todo caráter não pertencente à linguagem brainfuck é excluído.
Ao encontrar a instrução de entrada ',', o interpretador pausa a execução até que o usuário entre com um byte em hexadecimal.
O valor deve digitado como hexadecimal na caixa de texto 'entrada (hex)'. Para confirmar, o usuário deve clicar em 'entrar', que reativa o funcionamento do interpretador.
Sempre que se clica em 'entrar', o valor da caixa de texto 'entrada (hex)' é apagado.
A instrução de saída '.' grava valor na célula atual na caixa de texto saída, em formato hexadecimal.
Neste simulador, uma instrução brainfuck é executada a cada X ms. O valor de X deve ser informado na caixa de texto 'tempo (ms)', que aceita entre 5 e 2000 ms.
Antes de iniciar a execução do programa, o interpretador verifica se todos os loops estão bem formados, isto é, se foram abertos com um '[' e fechados com um ']'.