• トップ
  • ブログ一覧
  • 【第1回】Brainfuckを実装しながら学ぶC++【Brainfuckとは】
  • 【第1回】Brainfuckを実装しながら学ぶC++【Brainfuckとは】

    広告メディア事業部広告メディア事業部
    2020.12.08

    IT技術

    第1回目~Brainfuckを実装しながらC++学ぼう

    本連載では、「Brainfuck」の特性を理解しながら、実際に Brainfuck インタプリタを作成していきたいと思います!

    実は、Brainfuck を理解するということは、C/C++ でつまずきがちな「ポインタの概念を理解する」ということにつながります。

    つまり、Brainfuck インタプリタの実装は、プログラミング言語を深く学習するのに、もってこいの題材だということ。

    今まで、C/C++ を避けていたプログラマの皆さん!

    これを機に、C/C++ をマスターしながら、Brainfuck もマスターしていきましょう!

    Brainfuckとは

    Brainfuck (またはBrainf*ck) は、実用性を無視した、難読プログラミング言語 (通称 Esolang ) に分類されます。

    単なるユーモアプログラミング言語でありながら、チューリング完全 (≒なんでもプログラミング可能) な言語でもあるのです。

    例えば、「Hello, world!」と出力させたければ、Brainfuck では以下のように記述します。

    1+++++++++[->++++++++>+++++++++++>+++++<<<]>.>++.+++++++..+++.>-.
    2------------.<++++++++.--------.+++.------.--------.>+.

    見た目は、何をしているのか、さっぱりですね…。

    にもかかわらず、やっていることは、大したことありません!(笑)

    Brainfuckの基本を学ぼう

    連載第1回目では、まずは Brainfuck の仕組みを理解していきましょう!

    Brainfuck には、8つの命令が存在します。

    Brainfuckの命令

    +ポインタの指す値を1加算する
    -ポインタの指す値を1減算する
    >ポインタを1つ進める
    <ポインタを1つ戻す
    [ループ始まり:ポインタの指す値が0ならば] を指すポインタの一つ先に移動
    ]ループ終わり:[ を指すポインタに移動
    .ポインタの値をASCIIコードで変換して出力
    ,入力を受け取る

    以上の8つの命令で、Brainfuck は成り立っているのです。

    これ以外は、全てコメントとみなされます。

    さて、ここで「ポインタ」という概念が出てきました。

    ポインタについて、簡単に説明します!

    ポインタ (Pointer)

    ポインタとは、その名の通り「指すもの」を表します。

    何を指しているかというと、メモリ番地です。

    プログラミングの世界では、変数や関数を読み取るとき、その内容をメモリに保存します。

    例えば、4バイト分のメモリを使用する整数型のint であれば、次のように保持されます。

    4バイト分のメモリを使用する整数型のintの表示

    これら変数にアクセスするときは、メモリ番地をもとに参照しますよね?

    そのメモリ番地を指すのが、ポインタです。

    この場合、変数num のポインタは「4」であり、「メモリ番地 4 」ということになります。

    そこに格納されている値が、「123 (=0x007b)」ということです (「0x」は16進数)。

    つまり、変数にアクセスしたときは、「まずはポインタで、メモリのどこに格納されているかを探し、その値を読み取る」というプロセスが起こっているわけですね!

    ちなみに Brainfuck では、ポインタの初期値は「0」で、値も全て「0」です。

    Brainfuckを実際に書いてみよう

    では次に、実際に書きながら理解しましょう。

    インタプリタは、WEBrainfuck のようなブラウザで動作するタイプでもいいですし、インタプリタをお手持ちの PC にインストールするタイプでも構いません。

    macOS であれば、

    1$ brew install brainfuck

    で、できます。

    Windows であれば、以下のリンクから、実行するでもいいでしょう。

    【BFI.exe】
    http://esoteric.sange.fi/brainfuck/compiled/win/BFI.exe

    とりあえず 「H」 を出力させる

    「Hello, world!」の前に、まずは一文字目の「H」を出力させてみましょう!

    「H」は、ASCII コードでは、10進数で「72」です。

    したがって、以下のようにポインタの指す値を「+」で72回インクリメントして、「.」で出力させれば良いのです。

    1++++++++++++++++++++
    2++++++++++++++++++++
    3++++++++++++++++++++
    4++++++++++++.

    これで「H」が出力されます。

    ...が、この調子で「Hello, world!」を出力させようとすると、まずそうな雰囲気が漂ってきますね(笑)

    そこで、[] の出番です。

    ループで綺麗に書く

    Brainfuck にも、Brainfuck らしい綺麗なコード、というものがあります。

    [ は、最初に解説したように、今ポインタが指している値が「0」であれば、] の一つ後へ飛ぶ命令。

    そして ] は、 [ に飛ぶ命令です。

    これを使って、スマートに「H」を出力してみましょう

    1++++++++++     # ループカウンタ
    2[->+++++++<]   # 7x10 = 70回インクリメント
    3>++.           # +2 して出力

    これでも「H」が出力されるはずです。

    記法はこの限りではありませんが、[] を使うだけで、Brainfuck らしいコードになります。

    このとき、0番地目のメモリはループカウンタ、1番地目のメモリは「H」の ASCII コードを保持しています。

    さらに細かく紐解くと、以下のような感じ。

    1++++++++++     # ループカウンタ
    2[
    3    ->         # ループカウンタを一つ減らしてポインタを右シフト
    4    +++++++    # +10
    5    <          # ポインタをループカウンタへ移動
    6]   
    7>++.           # +2 して出力

    ここまでくれば、あなたはもう Brainfucker ですね!

    Hello, world!

    それでは「Hello, world!」に挑戦しましょう。

    各 ASCII コードは以下になります。

    H72
    e101
    l108
    o111
    ,44
    [スペース]32
    w119
    r114
    d100
    !33

    メモリの使い方によって、実装方法はたくさんありますので、ここでは一例を示します。

    1++++++++++[->+++++++<]>++.     # 10 × 72 = 72
    2>++++++++++[->++++++++++<]>+.  # 10 × 101 = 101
    3<+++[->++<]>+.                 # 1013 × 21 = 108
    4.                              # 108
    5+++.                           # 1083 = 111
    6<<<++++[->-------<]>.          # 724 × 7 = 44
    7<+++[->----<]>.                # 442 × 4 = 32
    8>++[->++++<]>.                 # 1112 × 4 = 119
    9<++[->----<]>.                 # 1112 × 4 = 111
    10+++.                           # 1113 = 114
    11<++[->---<]>.                  # 1142 × 3 = 108
    12<++[->----<]>.                 # 1082 × 4 = 100
    13<<+.                           # 321 = 33

    冒頭の例とは違った例で、できるだけループを使うようにしてみました。

    ちなみに、コメントの+ーは、わざと全角にしています。

    1行につき一文字です。

    これを改行なしで書くと、さらに Brainfuck 感が出ますね(笑)

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

    次回からはBrainfuckのインタプリタを作る

    さて、Brainfuck の仕組みがわかったところで、いよいよ Brainfuck をデコードするインタプリタを作ってみましょう!

    ポインタを扱うには、C/C++ が最適ですので、C/C++ の知識も同時に身につけていきます。

    第2回へつづく!

    今回は、実装する前の予備知識として、Brainfuck を解説しました。

    次回からは、いよいよ C/C++ を使って、インタプリタの実装をしていきます。

    本連載では、今まで C/C++ を触ったことがないような人にも、理解できるような内容になっているので安心してくださいね!

    それでは、次回をお楽しみに!

    第2回はこちら!

    【第2回】Brainfuckを実装しながら学ぶC++【実装してみよう!前編】2020.12.15【第2回】Brainfuckを実装しながら学ぶC++【実装してみよう!前編】第2回~Brainfuckを実装しながら学ぶC++連載「Brainfuckを実装しながら学ぶC++」シリーズの第2回目...

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

    featureImg2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
    featureImg2020.07.27IT・コンピューターの歴史特集IT・コンピューターの歴史をまとめていきたいと思います!弊社ブログにある記事のみで構成しているため、まだ「未完成状態」...

    広告メディア事業部

    広告メディア事業部

    おすすめ記事