2011年5月7日土曜日

brainf*ckインタプリタ

C++の練習なども兼ねて、有名な難解プログラミング言語であるbrainf*ckのインタプリタを作った。
DLはこちら→リンク
brainfuckについては、こちらが詳しいです


brainfuckは8つの命令のみを持つチューリング完全な言語で、
それぞれの命令をC風に置き換えると

 + : *ptr++
 - : *ptr--
 > : ptr++
 < : ptr--
 . : putchar(*ptr)
 , : *ptr = getchar()
 [  : while(*ptr){
 ]  : }
となってます。

で、作成したのがこれ



入力はテキストファイルになってます。

コードはこちら
#include <iostream>
#include <fstream>
#include <string>
#include <stack>
using namespace std;

const int MAX_MEMORY = 256;
unsigned char str[MAX_MEMORY] = { 0 };
unsigned char *ptr = str;

stack<int> st;

int main( int argc, char *argv[] )
{
 unsigned char buffer;
 int ptr_back = NULL;
 ifstream code;

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

 if ( code.fail() ) return 0;

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

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

 while ( code >> buffer )
 {
  switch (buffer) {
  
  case '+':
   (*ptr)++;
   break;
  
  case '-':
   (*ptr)--;
   break;
  
  case '>':
   ptr++;
   break;
  
  case '<':
   ptr--;
   break;
  
  case '.':
   putchar(*ptr);
   break;
  
  case ',':
   *ptr = getchar();
   break;
  
  case ']':
   ptr_back = static_cast<int>( code.tellg() );
   code.seekg( st.top() - 1 );
   st.pop();
   break;
  
  case '[':
   st.push( static_cast<int>( code.tellg()) );
   if ( *ptr == 0 )
   {
    if ( ptr_back == NULL ) {
     while ( code >> buffer )
      if ( buffer == ']' )
      {
       st.pop();
       break;
      }
    }
    st.pop();
    code.seekg( ptr_back );
    ptr_back = NULL;
   }
   break;
  
  default:
   break;
  }
 }

 code.close();
 
 printf("\n\n");
 for( int i = 0; i < MAX_MEMORY; ++i )
 {
  printf("%02X  ", str[i]);
  if ( !((i+1) % 16) )
   printf( "\n" );
 }
 return 0;
}

メモリの中身を見ながらステップ実行できたりしたら素敵ですよね。
実装予定はないですけれどw