2011年5月8日日曜日

brainf*ckインタプリタその2

前回に引き続きbrainf*ckインタプリタです。
今回は完全にC++の勉強用。クラスを使ってみたかっただけのものです。


以下、コード
#include <iostream>
#include <fstream>
#include <string>
#include <stack>
#define MAX_MEMORY 256

class brainfuckVM
{
private:
 unsigned char memory[MAX_MEMORY];
 unsigned char *pc;
public:
 brainfuckVM(){
  memset( memory, 0x00, MAX_MEMORY * sizeof(unsigned char) );
  pc = memory;
 }

 void incValue() { ++(*pc); }
 void decValue() { --(*pc); }
 void incPointer()
 {
  if ( pc == &memory[MAX_MEMORY] ) {
   std::cerr << "invaild error\n";
   exit( 8 );
  }
  ++pc;
 }
 
 void decPointer()
 {
  if ( pc == memory ) {
   std::cerr << "invaild error\n";
   exit( 8 );
  }
  --pc;
 }

 void input( unsigned char ch ){ *pc = ch; }
 void output() { std::cout << *pc; }

 bool isValue()
 {
  if ( *pc == 0 ) return false;
  else return true;
 }

 void dumpMemory()
 {
  int i = 0;
  for( pc = memory; i < MAX_MEMORY; ++i, ++pc )
  {
   printf("%02X  ", *pc );
   if ( !((i+1) % 16) )
    printf( "\n" );
  }
 }


};

std::stack<int> st;

int main( int argc, char **argv )
{
 unsigned char buffer;
 int jump_pointer = NULL;
 std::ifstream code;

 brainfuckVM vm;

 if( argc != 2 )
 {
  std::string filename;
  std::getline( std::cin, filename );
  code.open( filename.c_str() );
 }
 else code.open( argv[1] );

 if( code.fail() )
 {
  std::cerr << "file open error\n";
  exit( 8 );
 }

 while( code >> buffer ) std::cout << buffer;
 printf( "\n\n" );

 code.clear();
 code.seekg( 0, std::ios::beg );

 while( code >> buffer )
 {
  switch (buffer) {
  case '+':
   vm.incValue(); break;
  case '-':
   vm.decValue(); break;
  case '>':
   vm.incPointer(); break;
  case '<':
   vm.decPointer(); break;
  case '.':
   vm.output(); break;
  case ',':
   vm.input( static_cast<unsigned char>( getchar() ) );
   break;
  case ']':
   jump_pointer = static_cast<int>( code.tellg() );
   code.seekg( st.top() - 1 );
   st.pop();
   break;
  case '[':
   st.push( static_cast<int>( code.tellg() ));
   if ( jump_pointer == NULL )
   {
    while ( code >> buffer )
    {
     if ( buffer == ']' )
     {
      jump_pointer = static_cast<int>( code.tellg() );
      code.seekg( st.top() - 1 );
      st.pop();
      break;
     }
    }
    if ( code.eof() )
    {
     std::cerr << "not found ']'\n";
     exit( 8 );
    }
   }
   else if ( !vm.isValue() )
   {
    st.pop();
    code.seekg( jump_pointer );
    jump_pointer = NULL;
   }
   break;
  default:
   break;
  }
 }

 code.close();
 
 printf("\n\n");
 vm.dumpMemory();
 std::cout << "\nPress Enter...";
 getchar();
 return 0;
}
例外を使ってなかったり同じ記述が複数回出てたりしてますね。反省。
それに'['の処理のネストが深すぎるのも悩みどころです……