sábado, 1 de agosto de 2009

Como implementar um interpretador de brainfuck - parte 3

Até aqui, o programa já abre um arquivo e coloca seu conteúdo na memória. Só falta fazê-lo analisar e interpretar o arquivo.

Adicione, antes de do { c = getchar(); } while ((c != '\n') && (c != EOF)); e return 1;, uma variável de 30.000 elementos, chamada pilha, a qual será usada para armazenar as células (as variáveis do brainfuck), uma variável chamada pos, com a quantidade de elementos informados pela variável colchetes, a qual será usada para guardar as localizações das estruturas de repetição e, uma variável chamada ptr, a qual será usada como um indicador (ou ponteiro) para a célula selecionada. Também crie um estrutura de repetição para contar os “[” e guardar suas localizações, para uso futuro. Ficará assim:

#include <stdio.h>
#include <stdlib.h>
#include <string.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
   }

   fseek(arquivo, 0, SEEK_END);
   int tamanho = ftell(arquivo); // Offset do fim do arquivo, que equivale ao tamanho do arquivo
   rewind(arquivo); // Rebobina o arquivo

   // Aloca memória, com um byte adicional para o nulo (usado em strings em C)
   char *fonte = (char *) malloc(tamanho + 1);
   if (fonte == NULL) // Verifica se consegui alocar memoria
   {
      puts("ERRO: Não há memória o suficiente!");
      do { c = getchar(); } while ((c != '\n') && (c != EOF));
      return 1;
   }

   memset(fonte, 0, tamanho * sizeof(char)); // Preencherá a variável fonte com zeros (para "limpar")
   size_t size = fread(fonte, 1, tamanho, arquivo);
   fonte[tamanho] = 0; // Põe o sinal de fim (nulo)
   if (size != tamanho * sizeof(char))
   {
      puts("ERRO: Não foi possível ler o arquivo!");
      do { c = getchar(); } while ((c != '\n') && (c != EOF));
      return 1;
   }

   int colchetes = 0, i;
   for (i = 0; i < tamanho; i++)
   {
      if (fonte[i] == '[')
      {
         colchetes++;
      }
      else if (fonte[i] == ']')
      {
         if (colchetes == 0) // Se nenhuma estrutura '[' está aberta
         {
            puts("ERRO: A estrutura de repetição ']' não foi aberta!");
            do { c = getchar(); } while ((c != '\n') && (c != EOF));
            return 1;
         }
         else
         {
            colchetes--;
         }
      }
   }
   if (colchetes > 0) // Se alguma estrutura '[' não foi fechada
   {
      puts("ERRO: A estrutura de repetição '[' não foi fechada!");
      do { c = getchar(); } while ((c != '\n') && (c != EOF));
      return 1;
   }

   unsigned char pilha[30000]; // Equivalente a aproximadamente 30 KB
   memset(pilha, 0, 30000 * sizeof(unsigned char));

   int backup = 0, ptr = 0, pos[tamanho];
   colchetes = 0;
   for (i = 0; i < tamanho; i++)
   {
      if (fonte[i] == '[')
      {
         backup = i;

         while (i < tamanho)
         {
            if (fonte[i] == '[')
            {
               colchetes++;
            }
            else if (fonte[i] == ']')
            {
               colchetes--;
            }
            if (colchetes == 0)
            {
               break;
            }
            i++;
         }
         pos[i] = backup;
         pos[backup] = i;
         i = backup;
      }
   }

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

Depois disso, adicione uma estrutura de repetição, de preferência uma do tipo for, com a condição de repetir até o índice apontar para o último elemento da variável fonte e, dentro dela coloque uma condição, a qual se o elemento examinado for igual a “+”, deverá incrementar o valor da célula selecionada. Em seguida, adicione outra condição, a qual se o elemento examinado for igual a “.”, deverá por na tela o conteúdo da célula selecionada. Ficará assim:

#include <stdio.h>
#include <stdlib.h>
#include <string.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
   }

   fseek(arquivo, 0, SEEK_END);
   int tamanho = ftell(arquivo); // Offset do fim do arquivo, que equivale ao tamanho do arquivo
   rewind(arquivo); // Rebobina o arquivo

   // Aloca memória, com um byte adicional para o nulo (usado em strings em C)
   char *fonte = (char *) malloc(tamanho + 1);
   if (fonte == NULL) // Verifica se consegui alocar memoria
   {
      puts("ERRO: Não há memória o suficiente!");
      do { c = getchar(); } while ((c != '\n') && (c != EOF));
      return 1;
   }

   memset(fonte, 0, tamanho * sizeof(char)); // Preencherá a variável fonte com zeros (para "limpar")
   size_t size = fread(fonte, 1, tamanho, arquivo);
   fonte[tamanho] = 0; // Põe o sinal de fim (nulo)
   if (size != tamanho * sizeof(char))
   {
      puts("ERRO: Não foi possível ler o arquivo!");
      do { c = getchar(); } while ((c != '\n') && (c != EOF));
      return 1;
   }

   int colchetes = 0, i;
   for (i = 0; i < tamanho; i++)
   {
      if (fonte[i] == '[')
      {
         colchetes++;
      }
      else if (fonte[i] == ']')
      {
         if (colchetes == 0) // Se nenhuma estrutura '[' está aberta
         {
            puts("ERRO: A estrutura de repetição ']' não foi aberta!");
            do { c = getchar(); } while ((c != '\n') && (c != EOF));
            return 1;
         }
         else
         {
            colchetes--;
         }
      }
   }
   if (colchetes > 0) // Se alguma estrutura '[' não foi fechada
   {
      puts("ERRO: A estrutura de repetição '[' não foi fechada!");
      do { c = getchar(); } while ((c != '\n') && (c != EOF));
      return 1;
   }

   unsigned char pilha[30000]; // Equivalente a aproximadamente 30 KB
   memset(pilha, 0, 30000 * sizeof(unsigned char));

   int backup = 0, ptr = 0, pos[tamanho];
   colchetes = 0;
   for (i = 0; i < tamanho; i++)
   {
      if (fonte[i] == '[')
      {
         backup = i;

         while (i < tamanho)
         {
            if (fonte[i] == '[')
            {
               colchetes++;
            }
            else if (fonte[i] == ']')
            {
               colchetes--;
            }
            if (colchetes == 0)
            {
               break;
            }
            i++;
         }
         pos[i] = backup;
         pos[backup] = i;
         i = backup;
      }
   }

   for (i = 0; i < tamanho; i++)
   {
      switch (fonte[i])
      {
         case '+':
            pilha[ptr]++;
            break;

         case '.':
            putchar(pilha[ptr]);
            break;
      }
   }

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

« parte anterior próxima parte »

Postagens relacionadas

0 comentários:

Postar um comentário