連載
» 2017年07月25日 05時00分 UPDATE

Dev Basics/Keyword:Brainfuck

Brainfuckは8種類の命令とバイト配列、バイト配列を参照するポインターで構成される極めてシンプルなプログラミング言語。コードの可読性は著しく低い。

[かわさきしんじ,Insider.NET編集部]
「Dev Basics/Keyword」のインデックス

連載目次

 Brainfuckはわずか8種類の命令、3万バイト以上のバイト配列、バイト配列を参照するポインターで構成されるプログラミング言語。記述されるコードが難解なものになることで有名。また、「Brainf*ck」などと呼称される場合もある。

Brainfuckが持つ命令

 Brainfuckには以下に示す8つの命令(インストラクション)があり、これらを使用してバイト配列を参照するポインターと、ポインターが指すバイト配列内の要素を操作することで処理を進めていく。

  • >: ポインターをインクリメント(配列内の次の要素を指す)
  • <: ポインターをデクリメント(配列内の前の要素を指す)
  • +: ポインターが指す位置のデータをインクリメント
  • -: ポインターが指す位置のデータをデクリメント
  • .: ポインターが指す位置のデータを出力する
  • ,: 1バイトのデータの入力を受け取り、ポインターが指す位置に保存
  • [: ポインターが指す位置のデータが0であれば、対応する「]」の後までジャンプ
  • ]: 対応する「[」にジャンプ

 ポインターはバイト配列の先頭を指すように初期化される。また、バイト配列の要素はゼロに初期化される。[]の組み合わせは、ポインターをpと表現したときのC言語における「while (*p) { …… }」ループに相当する。

 簡単な(?)例として、コンソールに文字「@IT」を出力するプログラムを以下に示す。

++++++++[>++++++++<-]>.
+++++++++.
+++++++++++.


「@IT」と出力するBrainfuckプログラム

 ここではコードを3行に分割したが、それらの各行で「@」「I」「T」の文字を出力している(行末の「.」で出力)。その前にある記号列でバイト配列を指すポインターと、バイト配列の要素の値を操作している。

 ここでは最初の行に着目して、何を行っているかを説明しよう。最初の「++++++++」(「+」記号が8つ)は、バイト配列の先頭要素の値を8回インクリメントしている(上述したように「+」は「ポインターが指す位置のデータをインクリメント」する命令)。よって、この時点でバイト配列は次のようになる。

「++++++++」を実行した時点でのバイト配列の状態 「++++++++」を実行した時点でのバイト配列の状態

 その次の「[……]」という箇所でループ処理を行っている。ループの内部では「>++++++++<-」という処理を行っている。「>」はポインターをインクリメントする命令、「+」はポインターが指す位置のデータをインクリメントする命令、「<」はポインターをデクリメントする命令、「-」はポインターが指す位置のデータをデクリメントする命令であった。つまり、これは「ポインターをインクリメントして、バイト配列の次の位置を指すようにして、その位置のデータを8回インクリメントする。インクリメントが終わったらポインターをデクリメントして、バイト配列の前の位置(先頭要素)を指すようにして、その値をデクリメントする」ことを意味している。これを図に表すと次のようになる。

ループ内部の処理 ループ内部の処理

 上記の処理が終わると「]」により、対応する「[」まで処理がジャンプする。「[」はポインターが指す位置にあるデータが0であれば、対応する「]」までジャンプをして処理を継続するが、ここではデータが7なので、ループ内の処理を再度実行することになる。よって、これは「バイト配列の先頭要素にセットした回数だけ、ループ内部の処理を行う」ことになる。最終的にはバイト配列の2番目の要素の値は「8回のインクリメント×8回のループ」により「64」となる。

ループ終了後のバイト配列の状態 ループ終了後のバイト配列の状態

 ループの後には「>.」という2つの命令がある。「>」によりポインターがインクリメントされて、「64」を指すようになり、「.」により「@」記号(「@」記号のASCIIコード値は「64」)が出力されるというわけだ。もちろん「+」記号を64個書き連ねて(最後に「.」を記述して)もよいのだが、ループを使えば、比較的簡単に同じ処理を行える。

 その後は、「I」と「T」のASCIIコード値になるように、「+」記号を使ってバイト配列の2番目の要素をインクリメントしていき、出力を行っているだけだ。

 ここまでで8つの命令のうち7つの説明が終わった。最後に残っている入力(,)を使うとコンソールからデータを受け取れる。例えば、以下は1文字のエコーを行うプログラムだ。

,.


1文字のエコーを行うプログラム

 ポインターの操作を行っていないので、このプログラムは「,」により1バイトのデータを入力から受け取ってバイト配列の先頭要素に保存し、「.」でそのデータを出力することになる。以下のようにすれば、エコーを続けるようになる。

+[,.]


無限にエコーを行うプログラム

 ここではバイト配列の先頭要素の値を1にして、ループに入っている。ループでは配列の先頭要素をバッファーとして使い、「,」でそこにデータを受け取ったら、それをそのまま「.」で出力している。入力された値が「0」(数値)の場合には出力後にプログラムが終了するようになっている。

Brainfuckの処理系

 Windowsで使えるBrainfuckの処理系は「The Brainfuck Archive」などから入手可能だ。「The Brainfuck Archive」にはコンパイル済みの処理系もある。以下は「The Brainfuck Archive」で配布されているインタープリタを実行している様子だ。

Brainfuckインタープリタの実行画面 Brainfuckインタープリタの実行画面

 また、Brainfuck Developerで配布されている処理系では、バイト配列の状態がビジュアルに確認できるので、Brainfuckプログラムが実際にどのような操作を行っているかが分かりやすい。

Brainfuck Developerの実行画面 Brainfuck Developerの実行画面

 また、Brainfuckから派生した言語も多い。これについてはWikipediaの「Brainfuck」にある「派生言語」を参照されたい。


 Brainfuckは8種類の命令とバイト配列、ポインターで構成される極めてシンプルなプログラミング言語。コードの可読性は低いが、シンプルである分、さまざまな派生言語が登場したり、「Brainfuck Golf」のようになるべく短いステップで何らかの処理を記述するコンテストが開かれたりするなど、プログラミングの楽しみが詰まった言語でもある。

参考資料

  • Brainfuck: Brainfuckを紹介したページ
  • Brainfuck: 日本語版のWikipediaにあるBrainfuckの解説
  • Brainfuck: 英語版のWikipediaにあるBrainfuckの解説
  • Brainf*ck: Brainfuckのサンプルプログラムとその解説。加算、乗算、条件分岐などをどう記述すればよいかが分かる
  • The Brainfuck Archive: Brainfuckの処理系のアーカイブ
  • Brainfuck Developer: Brainfuck Developerの配布サイト

「Dev Basics/Keyword」のインデックス

Dev Basics/Keyword

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

Focus

- PR -

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。