/* The Null Neuron Interpreter - A brainfuck interpreter
 * By Daniel D'Agostino
 * Monday 20th October 2008
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

int getFileSize(const char * filename)
{
  struct stat fs;

  FILE * file = fopen(filename, "r");
  if (file == NULL)
  {
    fprintf(stderr, "Error: Bad filename");
    exit(-1);
  }
  if (fstat(fileno(file), &fs) == -1)
  {
    fprintf(stderr, "Error: Could not check filesize");
    exit(-1);
  }
  else
    return fs.st_size;
  fclose(file);
}

int countPtrIncrements(const char * buffer, int filesize)
{
  int i = 0;
  int count = 0;
  for (i = 0; i < filesize; i++)
    if (buffer[i] == '>')
      count++;
  return count;
}

int main(int argc, char ** argv)
{
  /* variable declarations */

  char * filename = NULL;
  FILE * file = NULL;
  int filesize = 0;

  char * ptr = NULL;
  char * firstbyte = NULL;
  int ptrIncrements = 0;

  int i = 0;
  char * buffer;
  int lastbracket = -1;

  /* input parameter: one expected for file */

  if (argc != 2)
  {
    fprintf(stderr, "Error: No input file\n");
    exit(1);
  }
  else
    filename = argv[1];

  /* load stuff from file */

  filesize = getFileSize(filename);
  printf("Reading %d bytes... ", filesize);

  file = fopen(filename, "r"); /* already passed validation */
  buffer = (char *) malloc(filesize);
  fread(buffer, 1, filesize, file);
  ptrIncrements = countPtrIncrements(buffer, filesize);
  firstbyte = (char *) malloc(ptrIncrements);
  ptr = firstbyte;
  memset(ptr, 0, ptrIncrements);
  fclose(file);

  printf("done.\n");

  /* parse */

  printf("Parsing...\n");

  for (i = 0; i < filesize; i++)
  {
    switch(buffer[i])
    {
      case '>': ++ptr; break;
      case '<':
        if (ptr == firstbyte)
          fprintf(stderr, "Error: Negative pointer");
        else
          --ptr; break;
      case '+': ++(*ptr); break;
      case '-': --(*ptr); break;
      case '.': putchar(*ptr); break;
      case ',': *ptr = getchar(); break;
      case '[':
        lastbracket = i;
        if ((*ptr) == 0)
          while (buffer[i] != ']')
            i++;
          i++; /* skip ']' to next command */
        break;
      case ']':
        if ((*ptr) != 0)
          if (lastbracket == -1)
            fprintf(stderr, "Error: Bracket mismatch");
          else
            i = lastbracket;
      break;
      default: break;
    }
  }

  /* clean up and quit */

  free(buffer);
  free(firstbyte);
  exit(0);
}
