Criação e uso de um interpretador de script BrainFuck em C++

Como objeto de estudo, as diversas linguagens de programação exotéricas são muito válidas para programadores com uma certa experiência. Vale conhecer tais linguagens e saber o por quê de sua inviabilidade técnica. Aqui implementarei um interpretador de tal linguagem.

[ Hits: 9.979 ]

Por: Jean Marcel Duvoisin Schmidt em 07/10/2009


Introdução



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:
   

Páginas do artigo
   1. Introdução
Outros artigos deste autor
Nenhum artigo encontrado.
Leitura recomendada

Apreendendo a utilizar o GNU Debugger (parte 2)

LivreNFE - O emissor Nfe open source para Linux

Utilizando a biblioteca NCURSES - Parte III

Programando com uma granada de mão: uma visão da linguagem C

C - Include e Makefile

  
Comentários
[1] Comentário enviado por rafaelcosta em 07/10/2009 - 18:10h

então né?


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts