1. HOME
  2. ブログ
  3. IT技術
  4. 【第4回】Brainfuckを実装しながら学ぶC++【実装してみよう!後編】
【第4回】Brainfuckを実装しながら学ぶC++【実装してみよう!後編】

【第4回】Brainfuckを実装しながら学ぶC++【実装してみよう!後編】

第4回~Brainfuckを実装しながら学ぶC++

Brainfuckを実装しながら学ぶC++」シリーズも、今回を含めて、残り2回となりました!

ちなみに前回は、Brainfuck の実装にあたり、大枠を作っていきました。

今回は、Brainfuck インタプリタの核となる部分を、実装していきましょう!

メモリ操作命令「+ / - / > /<」の実装

まずは、比較的実装が簡単な、「+ / - / > / <」の命令から実装していきましょう。

値の加算命令「+」

すごくシンプルですね!

今ポインタが指しているメモリの値を、インクリメントしているだけです。

Braunfuck では、値が255を超えた (オーバーフローした) 場合は、値を「0」にする必要があります。

ですが unsigned char は、もともと「0~255」の範囲しか取りません。

つまり、オーバーフローした場合は勝手に「0」になるので、そういった処理は書かなくても OK ですね!

値の減算命令「-」

コードは「+」とほとんど同様です。

こちらもアンダーフローした場合、勝手に「255」になります。

ポインタの加算「>」

こちらは、オーバーフローの処理を、しっかりと記述してあげましょう。

今回の実装では、三項演算子「?」を使用した形で書いています。

これは、以下のコードと同様です。

ポインタの減算「<」

こちらも同様です。

MEMORY_SIZE-1 は、セグメンテーション違反に気をつけましょう。

入出力命令「 . / , 」の実装

次に、入出力命令を実装していきます。

C / C++ では、 #include <cstdio> を使えば、とてもシンプルに書けます。

ここまででデバッグをしてみよう

ここまで実装が終わると、ループを使わずに、Brainfuck コードを実行できるようになります。

例えば、「A」を出力するコード。

そして、アンダーフローを使った「z」の出力もできると思います。

他にも、ポインタの移動や入力も、自身で試してみると良いですね!

例えば、入力された文字をそのまま出力するコードは、

です。

ループ命令 [ ] の実装

ここが、Brainfuck インタプリタ実装において、もっとも難しいところです。

まずは実装する中で、考慮すべき点を列挙してみましょう。

  1. " [ " が来たら、それがあるコードポインタを保持しておく。
  2. " [ " の時点で、ポインタの指す値が0かどうかを確認する。
    → 0ならば、対応する " ] " の一つ後ろへ飛ぶ。
    → 0でなければ、そのままコードポインタを進める。
  3. " ] " が来たら、対応する " [ " へ飛ぶ。

以上の3点です。

ここで、ひと工夫が必要な部分は、ループのネストです。

" [ " と " ] "の対応関係を上手く実装する必要があります。

まずは、"[" のコードポインタを保持する配列を作りましょう。

大枠を作る

今回は、 std::stack<> を使用します。

その名の通り、LIFO (Last-In First-Out) なコンテナです。

そうしたら、命令に対応した処理を実装していきましょう。

ひとまず、「ポインタの値が0のとき」以外を作ります。

つまり実装するのは、「 " ] " が来たら対応する " [ " に飛ぶ 」です。

" [ " から " ] "に飛ぶ処理を実装する

先ほどの if 文の中身を、ここでは実装していきましょう。

" [ " と " ] " の対応関係は、ループの深さを保持する、 depth という変数を用いて実装していきます。

やっていることは、じっくりコード中のコメントを読むと、理解できるかと思います。

あとは、もう一度ビルドして完成です!

Brainfuck インタプリタが完成!

お疲れ様でした!

これにて、Brainfuck インタプリタが完成しました。

「意外と簡単!」と感じたのではないでしょうか?

最後に、動作確認もしてみましょう!

Hello, world!

以下のコードを、インタプリタに与えてみます。

上手くいきましたね!

皆さんはどうでしょうか?

他にも、いろいろ試してみましょう!

最短のHello, World!

最短の「Hello, Wolrd!」コードです。

アンダーフローへの対応と、多重ループの対応が上手くできていないと、しっかりと出力されないサンプルです。

さらに、走査回数が17,896ステップと、比較的難解な Brainfuck コードでもあります。

どうでしょうか?

上手く実装できていれば、C++ なので、かなり高速に所望の出力が得られると思います!

FizzBuzz

おまけとして、有名な言葉遊びも。

フィボナッチ数を延々と出力するコード

メモリがオーバフローするまで、出力してくれるコードはこちら。

番外編へつづく!

お疲れ様でした!

今回で、連載「Brainfuck を実装しながら学ぶ C++」のメインは、ひとまず終了になります。

次回最後となる番外編では、「出来上がったコードを改造」してみたいと思います!

本連載を通して少しでも、C / C++ に、そし て Brainfuck をはじめとする、Esolang にも興味を持っていただけたら幸いです。

本コードは、最初に定数として宣言していた命令を少し変えるだけで、オリジナル Esolang が作れますよ

ぜひ遊んでみてくださいね!

では、次回もお楽しみ!

最終コード

番外編はこちら!

第1回目はこちら!

こちらの記事もオススメ!


書いた人はこんな人

広告メディア事業部
広告メディア事業部
「好きを仕事にするエンジニア集団」の(株)ライトコードです!

ライトコードは、福岡、東京、大阪の3拠点で事業展開するIT企業です。
現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。
いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。

システム開発依頼・お見積もり大歓迎!

また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」「WEBディレクター」を積極採用中です!
インターンや新卒採用も行っております。

以下よりご応募をお待ちしております!
https://rightcode.co.jp/recruit

関連記事

採用情報

\ あの有名サービスに参画!? /

バックエンドエンジニア

\ クリエイティブの最前線 /

フロントエンドエンジニア

\ 世界を変える…! /

Androidエンジニア

\ みんなが使うアプリを創る /

iOSエンジニア