Existem coisas que se fazem por sua utilidade, um script bash para realização de backups é um exemplo clássico, outras devido ao fato de ser divertido, como desenvolver um plugin para o XMMS. Enfim, chegamos ao ponto em que existem coisas inúteis que programamos, que são bem chatas, mas o fazemos com o intuito único de mostrar aos outros que o fazemos. É aqui que o
BrainF**k se encaixa.
BrainF**k é uma linguagem de programação exotérica, voltada para mostrar para o programador como as coisas NÃO deveriam ser feitas. Trata-se de uma sintaxe absurdamente simples onde usa-se 8 operadores (no meu caso 10) para executar operações simples de IO e memória.
Aqui vai um exemplo de código em BF:
++++++++++[>++++++++>+++++++++++
>---------->+++>++++++++>+++++++
+++++>+++++++++++>++++++++++>+++
++++++++>+++<<<<<<<<<<-]>-.>--.>
++++.>++.>---.>---.>.>.>+.>+++.,
Este exemplo retirei da Wikipédia, trata-se de um HelloWorld extremamente simples. Vou discorrer um pouco sobre os operadores, em seguida pretendo mostrar-lhes a implementação de um interpretador, após vou explanar alguns algoritmos em BF através de alguns exemplos.
Então, se você não desistiu até agora, peço para que baixe o BrainF**K em:
Vamos então dar uma olhada nos operadores que temos disponíveis, e na sua estrutura de memória:
- + Este operador incrementa o valor do módulo de memória atualmente selecionado.
- - Este operador decrementa o valor de memória do módulo atualmente selecionado.
- > Este operador desloca para uma posição á direita a seleção do módulo de memória.
- < De forma análoga, este operador desloca a seleção para um módulo de memória a esquerda.
- [ Este operador coloca na pilha de retorno a posição atual de execução do programa.
- ] Caso o valor do módulo de memória atualmente selecionado seja diferente de 0 retorna o ultimo valor da pilha para o ponteiro de execução do programa.
- . Escreve o valor do módulo atual na tela usando os códigos ASCII.
- , Lê um código ASCII do teclado e coloca no módulo de memória selecionado.
- * Lê do teclado um inteiro e o coloca no módulo de memória selecionado (não contem na implementação original de BF).
- & Imprime o valor do módulo de memória selecionado como um número inteiro (não contem na implementação original de BF).
A memória é cíclica de 3000 posições, cada posição contendo 8 bits mais um ponteiro de execução de programa e uma pilha de retorno de instruções. Se você não usa um modem de 14,4 kbps, seu download do interpretador já deve ter terminado. Descompacte o arquivo com o comando:
tar -zxvf bfDOit.tar.gz
Em seguida entre na pasta e compile com os comandos:
cd bfDOit
$ ./build
E teste o executável gerado usando o comando:
./bfDOit imprime_lista.bf
Se ele não funcionar, provavelmente sua arquitetura de cpu não suporta as flags passadas para o gcc, tente remover algumas como -m3dnow ou -msse2, caso não funcione (ou você não saiba do que estou falando), rode simplesmente:
gcc bfmain.cpp -o bfDOit
Assegurando que tudo está funcionando, recomendo a cópia do executável para /bin (tenha certeza que seus privilégios são de root).
cp bfDOit /bin
Com isso agora todos os arquivos que você iniciar com a tag:
#!/bin/bfDOit
E tiverem permissão de execução poderão ser chamados por:
./nome_do_arquivo
Pronto, vamos começar analisando o programa soma.bf:
&>&[-<+>]<*
Primeiro lemos uma entrada numérica, passamos para o próximo módulo de memória e lemos outra entrada numérica, até aí tudo bem. Em seguida o operador '[' coloca a posição atual na pilha e decrementamos a memória atual, com o - voltamos ao primeiro número e o incrementamos, então vamos ao número atual e testamos se este ainda é maior que zero, se for, pegamos o valor da pilha e retornamos ao começo deste for, ao fim retorna-se ao módulo de memória inicial e imprime seu valor numérico na tela.
Agora vamos ao um programa um pouco mais elaborado:
+[>,--------------------------------.<]
Este programa lê um caractere ASCII do teclado e o passa para maiúsculo (não adianta nem tentar escrever algo diferente de letras minúsculas que não vai funcionar...). Analogamente este programa seta a memória atual para um, avança um módulo de memória, lê uma entrada ASCII do teclado, incrementa numericamente em 32, imprime este novo valor na tela e volta ao módulo anterior que estava setado em 1, então volta ao início loop.
Pronto, agora só resta dar uma olhada em outros exemplos que coloquei, criar seus novos e se vangloriar para os amigos por ter perdido mais um pouco de tempo. xD. The geek way of life...
Links úteis: