sábado, 1 de agosto de 2009

Como implementar um interpretador de brainfuck

Neste tutorial estarei abordando a implementação de um interpretador de brainfuck, tendo ênfase em abrir arquivos, interpretar argumentos da linha de comando e interpretar comandos de byte único de uma linguagem, usando a linguagem C/C++ (será compatível com ambas as linguagens). O código fonte foi testado no Linux e no Windows, e provavelmente também funcionará em outros sistemas.

Introdução

Este é meu primeiro tutorial para o meu blog, e tentarei explicar passo-a-passo a implementação de um interpretador simples, ainda que completo. Eu escolhi a linguagem brainfuck por ser uma linguagem conhecida e simples. Estarei usando o compilador GCC/MinGW e um editor de texto simples. Caso esteja usando o Windows e não saiba como instalar um compilador, baixe o Code::Blocks, um ambiente de desenvolvimento integrado que já vem com o MinGW pronto para uso.

Etapa 1

Abra um editor de texto não-formatado de sua preferência (como o Bloco de Notas do Windows, ou o Code::Blocks) e, comece escrevendo a função principal:

int main()
{
}

Depois disso, declare os parâmetros da função main(), o contador (argc) e a sequência de argumentos (argv), e adicione a função getchar(), para impedir que o programa se encerre automaticamente (isso não será necessário se você estiver usando o Code::Blocks), seguido do comando de retorno (return). Não esqueça de incluir a biblioteca stdio.h, onde se encontra a declaração da função getchar(). Ficará assim:

#include <stdio.h>

int main(int argc, char *argv[])
{
   int c;
   do { c = getchar(); } while ((c != '\n') && (c != EOF));
   return 0;
}

O parâmetro argc é um inteiro que conta quantos argumentos existem na linha de comando, incluindo o endereço do programa, e o argv é uma matriz com todos os argumentos da linha de comando. Se argc for igual a 2, o argv será {"programa", "argumento 2"}. Se argc for igual a 1, o argv será {"programa"}.

O loop "do" repete até uma determinada condição ser atingida, que neste caso é o usuário retornar uma quebra-de-linha ('\n', pressionando Enter) ou fim-de-arquivo (EOF, pressionando Ctrl+Z).

Por fim, o comando return retorna um valor inteiro para o sistema, que determina se o programa terminou bem (se retornar um valor igual a zero) ou não (se retornar um valor diferente de zero). Por convenção, é sempre deixada uma nova linha vazia, depois de fechar a função principal, mas isso não é obrigatório.

Agora que a base do programa está pronta, podemos começar. Declare um ponteiro do tipo FILE, chamado de arquivo. Adicione uma condição, para verificar a quantidade de argumentos e, dentro da condição, use a função fopen() para abrir o arquivo especificado pela linha de comando. Em seguida, adicione uma condição para verificar se o arquivo foi aberto com sucesso.

#include <stdio.h>

int main(int argc, char *argv[])
{
   int c;

   FILE *arquivo; // Deve-se usar o asterisco aqui, por ser ponteiro
   if (argc >= 2) // Se tiver 2 ou mais argumentos
   {
      arquivo = fopen(argv[1], "rb"); // Abre o arquivo especificado
      if (arquivo == NULL) // Se não conseguir abrir o arquivo
      {
         puts("ERRO: Não foi possível abrir o arquivo!");
         do { c = getchar(); } while ((c != '\n') && (c != EOF));
         return 1; // Encerra o programa
      }
   }
   else
   {
      return 0; // Encerra o programa
   }

   do { c = getchar(); } while ((c != '\n') && (c != EOF));
   return 0;
}

É muito importante verificar se o programa conseguiu abrir o arquivo, pois se não verificado, pode gerar problemas e fazer o programa encerrar de forma abrupta. Eu instruí o programa a abrir o arquivo indicado pelo segundo item da matriz argv (em C, o primeiro item é indicado por zero, o segundo por um, o terceiro por dois, e daí por diante). O primeiro item dessa matriz é o endereço do programa.

próxima parte »

Postagens relacionadas

0 comentários:

Postar um comentário