Brainf*ckでHelloWorld!を出力してみる
こんにちは。株式会社プラハCEOの松原です。
最近の弊社の社内勉強会では毎週1時間だけ集まって色んなものをモブプロして遊んでいます。前回までは簡易的な仮想DOMのロジックを自分たちで実装することでReactをより深く理解しようとしました。
仮想DOMの実装が終わって次のモブプロテーマを探していたところ、低レイヤー周りを勉強している弊社メンバーが
「BrainF*ckという難解プログラミング言語があるので、それで遊びませんか」
と提案してくれたので、今回の社内勉強会では早速bf(Brainf*ck。毎回fワード書いてると怒られそうなので以降は省略します)で遊んでみました
bfとは
そもそも言葉の由来としてbfは直訳で「頭をxxxxされる」、「頭の中をぐちゃぐちゃにされる、混乱する」という意味のスラングです
そこまで言うならbfというプログラミング言語は相当頭の中をぐちゃぐちゃにしてくれるんだろうな〜と期待しながら実際の構文を覗いてみました。Hello World!をbfでどうやって出力するのかと言うと...
>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]
>++++++++[<++++>-] <.>+++++++++++[<++++++++>-]<-.--------.+++
.------.--------.[-]>++++++++[<++++>- ]<+.[-]++++++++++.
一ミリも理解できない。なぜbfはこれほど意味のわからない構文になるのでしょうか?
bfが解釈する記号は8つのみ
それはbfが8つの記号しか理解しないからです:
> ポインタを1進める
< ポインタを1戻す
+ ポインタの指す要素の値を1増やす
- ポインタの指す要素の値を1減らす
. ポインタの指す要素の値を外に出力
, 外から値を入力して、 ポインタの指す場所へ入れる
[ ポインタの指す要素の値が 0 だったら対応する次の ] までジャンプ
] 対応する前の [ までジャンプ
なので4
みたいな数字を書いてもbfはそれを解釈せずすっ飛ばしてしまいます。数字の4を表現したければ、今のポインタが指し示している値を4回加算する必要があります
++++
bfはコンピュータにはとことん優しく人間にはとことん厳しい言語なので人間側の都合なんて考えちゃくれません
Hello World!を出力してみる
まずは H を出力してみる
当然 'hello world'
なんて文字列も存在しないので1つずつ値を加算してASCIIコードで表現しなければいけません。例えばH
はアスキーコードで「72」なので、+を72回書いてから.
で値を出力すれば良いわけですね
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
これでHが出力できました...と言いたいところですが鋭い方は気づいたかもしれません。実は上記のコードは間違えて72回ではなく71回しか+を書いてないので実際はGと出力されます。普段使っているプログラミング言語に対する感謝をヒシヒシと感じ始めてきたのではないでしょうか。
掛け算を使って省略する
いくらおふざけ言語とはいえ+を72回も書くのはエンジニアとして抵抗がありますよね。8回の+を9回繰り返すことで72を表現したいところ。それを実現しているのが次のコードです:
>+++++++++[<++++++++>-]<.
まず最初の>でポインタを1つ進めてアドレス[2]を指し示す状態にします。アドレス2の値に9を加算します。現在の状況は以下の通り:
アドレス | 1 | 2 |
3 | 4 | 5 |
---|---|---|---|---|---|
値 | 0 | 9 | 0 | 0 | 0 |
その後の[]はループ処理です。現在指し示しているアドレスの値が0以外なら[]内の命令が実行されます。今はアドレス2の値が9なので、[]内の命令が1度実行されます。
[]の中では<でポインタを1つ戻してアドレス1に8を加算します
アドレス | 1 |
2 | 3 | 4 | 5 |
---|---|---|---|---|---|
値 | 8 | 9 | 0 | 0 | 0 |
その後>でポインタを1つ進めてアドレス2の値から1を減算します
アドレス | 1 | 2 |
3 | 4 | 5 |
---|---|---|---|---|---|
値 | 8 | 8 | 0 | 0 | 0 |
そして再度[]の評価を行います。現在指し示しているアドレス2の値は8なので、[]内の命令がもう一度実行されます。実行した後の状態はこんな感じ:
アドレス | 1 | 2 |
3 | 4 | 5 |
---|---|---|---|---|---|
値 | 16 | 7 | 0 | 0 | 0 |
もう一度ループ処理が実行されるとこうなる:
アドレス | 1 | 2 |
3 | 4 | 5 |
---|---|---|---|---|---|
値 | 24 | 6 | 0 | 0 | 0 |
最終的にはアドレス2の値が0になるまで繰り返すので、こうなります:
アドレス | 1 | 2 |
3 | 4 | 5 |
---|---|---|---|---|---|
値 | 72 | 0 | 0 | 0 | 0 |
もうここまできたらお気づきの方も多いかもしれませんが、これは実は掛け算をしています。アドレス2の値(当初9)が0になるまでアドレス1の値に8を足し続けていくわけですから、こうして8*9=72を表現できるわけですね。頭良い!
bf構文を見慣れてくると >+[<+>-]
パターンを見れば「あ、掛け算してるな」と気付けるようになってきます。人生には一ミリも役立たないのですが、とても楽しいです。
bfではif文も表現できる
ちなみに8つの記号だけでif文も表現できます。こんな感じ:
,[>>+>+<<<-]>>>[<<<+>>>-]>+<<[-----[>]>>[<<<+++>>>[-]]
ただこれを言葉で解説するのは非常に疲れるので、弊社の社内勉強会で悪戦苦闘しながらif文を実装した様子を見てもらうか:
YouTubeのvideoIDが不正ですBasics of BrainF*ckを読んでみるのがオススメです
何のためにbfするのか
日頃自分たちが扱っているプログラミング言語がいかに有難い機能をたくさん搭載してくれているか気付けます。感覚的にはキャンプに近い。文明に染まり切った都会ボーイが自然の中であえて不便を楽しむことで文明の恩恵を再認識する・・・みたいな感覚
あとは頭の体操になるので、ぜひbfで遊んでみてください!
+++++ ++++[ ->+++ +++++ +<]>+ +++++ .<+++ [->++ +<]>+ ++++. <++++ +++[-
>---- ---<] >---- ----- ----. <++++ ++++[ ->+++ +++++ <]>++ +++++ ++++.
<+++[ ->--- <]>-- --.<+ +++++ ++[-> ----- ---<] >---- -.<++ +++++ +[->+
+++++ ++<]> +++++ +++++ ++.++ +..-- --.-- .++++ +.--- ----. <++++ ++++[
->--- ----- <]>-- ----- .<+++ +++++ [->++ +++++ +<]>+ +++++ .++++ +++++
.+++. <++++ +++++ [->-- ----- --<]> -.<++ +++++ +[->+ +++++ ++<]> +++++
.++++ +++++ .---- ---.+ +.+++ ++.-- ----- --..< +++[- >+++< ]>+++ +.+.<
+++++ ++++[ ->--- ----- -<]>- -.<++ +++++ ++[-> +++++ ++++< ]>+++ +++.<
+++[- >---< ]>--- --.<+ ++[-> +++<] >++.< +++[- >---< ]>--- .<+++ +++++
[->-- ----- -<]>- ----- --.<+ +++++ +++[- >++++ +++++ <]>++ .+.-- .---.
-.--- ----. <++++ ++++[ ->--- ----- <]>-- ----- .<+++ +++++ [->++ +++++
+<]>+ +++++ +++.+ ++++. +++++ +.<++ +[->- --<]> ----- -.+++ ++++. .----
---.- -.<++ ++[-> ++++< ]>+.+ .<+++ +[->- ---<] >---- .<+++ [->++ +<]>+
+.<++ +++++ +[->- ----- --<]> ----- ----- --.<+ +++++ ++[-> +++++ +++<]
>+++. <++++ [->++ ++<]> ++.-- -.--- ----- -.+++ +++.+ +++.< +++[- >---<
]>-.< +++[- >+++< ]>++. +++++ .<+++ +++++ +[->- ----- ---<] >---- ----.
<+++[ ->+++ <]>++ ++.<+ ++[-> ---<] >---- .<+++ +++++ +[->+ +++++ +++<]
>+++. <+++[ ->--- <]>-- -.--- ----. <++++ [->++ ++<]> +++.< +++++ +++[-
>---- ----< ]>--- ----- ----- .<+++ +++++ [->++ +++++ +<]>+ +++++ +++++
+.<++ +++++ ++[-> ----- ----< ]>--. <++++ +++++ [->++ +++++ ++<]> +++++
+++.< +++[- >---< ]>-.+ +++++ .<+++ +++++ +[->- ----- ---<] >---. <
+++++ +++[- >++++ ++++< ]>+++ +++++ +.<++ ++++[ ->--- ---<] >---- -.<++
+++++ +[->+ +++++ ++<]> +++++ +++.+ +++++ +.+.< +++[- >---< ]>--. <++++
++++[ ->--- ----- <]>-- ---.< +++++ +[->+ +++++ <]>++ +++.< +++++ +[->-
----- <]>-- ---.< +++++ +++[- >++++ ++++< ]>+++ +.<++ +[->+ ++<]> ++.-.
<++++ ++++[ ->--- ----- <]>-- ----- .<+++ +++++ [->++ +++++ +<]>+ +++++
+++++ ++.<+ +++++ +++[- >---- ----- <]>-- -.<++ +++++ +[->+ +++++ ++<]>
+++++ ++.-- .<+++ [->++ +<]>+ +++++ .<+++ +++++ +[->- ----- ---<] >---.
<++++ ++++[ ->+++ +++++ <]>++ .-.<+ ++[-> +++<] >++++ ..--- ----- -.-.<
+++++ +++[- >---- ----< ]>--- -.<++ +++++ +[->+ +++++ ++<]> +++++ +.+++
+++++ +.+++ .<+++ +++++ +[->- ----- ---<] >-.<+ +++++ +++[- >++++ +++++
<]>++ +++.- .---- ----- .---- -.--- ---.< ++++[ ->+++ +<]>+ .<+++ +++++
+[->- ----- ---<] >-.<+ +++++ ++[-> +++++ +++<] >++++ +++++ +++.< +++[-
>---< ]>--. <+++[ ->+++ <]>++ ++.-- ----- .<+++ [->++ +<]>+ ++++. <++++
[->-- --<]> ----. +++++ +.--. <
Discussion