Edited at

C++11でBrainf*ck【Better C】


Brainf*ckとは

以下の命令によって動く言語です。




  1. > ポインタをインクリメントする。ポインタをptrとすると、C言語の「ptr++;」に相当する。


  2. < ポインタをデクリメントする。C言語の「ptr--;」に相当。


  3. + ポインタが指す値をインクリメントする。C言語の「(*ptr)++;」に相当。


  4. - ポインタが指す値をデクリメントする。C言語の「(*ptr)--;」に相当。


  5. . ポインタが指す値を出力に書き出す。C言語の「putchar(*ptr);」に相当。


  6. , 入力から1バイト読み込んで、ポインタが指す先に代入する。C言語の「*ptr=getchar();」に相当。


  7. [ ポインタが指す値が0なら、対応する ] の直後にジャンプする。C言語の「while(*ptr){」に相当。


  8. ] ポインタが指す値が0でないなら、対応する [ (の直後[1])にジャンプする。C言語の「}」に相当[2]。
    (引用: Wikipedia Brainfuck)


使用する命令が8個しかないのが非常に特徴的ですね。

では、実装していきましょう。


ソースコード(Visual C++)


Source.cpp

#include <cstdio>

#include <cstdint>
#include <string>

int main(int argc, char *argv[])
{
//ファイルが指定されていない時のエラー処理
if (argc != 2) {
std::printf("開くファイルを指定してください。\n");
return -1;
}
//ファイルが開けない時のエラー処理
std::FILE *fp = nullptr;
if (fopen_s(&fp, argv[1], "r")) {
std::printf("ファイルを開くことが出来ません。\n");
return -1;
}

//コードを読み取って格納
char read_char;
std::string code{};
while ((read_char = std::fgetc(fp)) != EOF) {
code.push_back(read_char);
}
std::fclose(fp);

//コードを処理
constexpr std::size_t buffer_size = 30000;
char buffer[buffer_size]{};
std::size_t buffer_ptr = 0;
std::int_fast32_t loop = 0;

const std::size_t code_len = code.size();
for (std::size_t code_ptr = 0; code_ptr < code_len; ++code_ptr) {

switch (code[code_ptr]) {
case '>':++buffer_ptr; break;
case '<':--buffer_ptr; break;
case '+':++buffer[buffer_ptr]; break;
case '-':--buffer[buffer_ptr]; break;
case '.':std::putchar(buffer[buffer_ptr]); break;
case ',':buffer[buffer_ptr] = std::getchar(); break;
case '[':
if (buffer[buffer_ptr] != 0) break;
for (++code_ptr; loop > 0 || code[code_ptr] != ']'; ++code_ptr) {
if (code[code_ptr] == '[') ++loop;
if (code[code_ptr] == ']') --loop;
}
break;
case ']':
if (buffer[buffer_ptr] == 0) break;
for (--code_ptr; loop > 0 || code[code_ptr] != '['; --code_ptr) {
if (code[code_ptr] == ']') ++loop;
if (code[code_ptr] == '[') --loop;
}
--code_ptr;
break;
}
}
return 0;
}



ソースコード(その他 C++)


Source.cpp

#include <cstdio>

#include <cstdint>
#include <string>

int main(int argc, char *argv[])
{
//ファイルが指定されていない時のエラー処理
if (argc != 2) {
std::printf("開くファイルを指定してください。\n");
return -1;
}
//ファイルが開けない時のエラー処理
std::FILE *fp = nullptr;
if ((fp = std::fopen(argv[1], "r")) == nullptr) {
std::printf("ファイルを開くことが出来ません。\n");
return -1;
}

//コードを読み取って格納
char read_char;
std::string code{};
while ((read_char = std::fgetc(fp)) != EOF) {
code.push_back(read_char);
}
std::fclose(fp);

//コードを処理
constexpr std::size_t buffer_size = 30000;
char buffer[buffer_size]{};
std::size_t buffer_ptr = 0;
std::int_fast32_t loop = 0;

const std::size_t code_len = code.size();
for (std::size_t code_ptr = 0; code_ptr < code_len; ++code_ptr) {

switch (code[code_ptr]) {
case '>':++buffer_ptr; break;
case '<':--buffer_ptr; break;
case '+':++buffer[buffer_ptr]; break;
case '-':--buffer[buffer_ptr]; break;
case '.':std::putchar(buffer[buffer_ptr]); break;
case ',':buffer[buffer_ptr] = std::getchar(); break;
case '[':
if (buffer[buffer_ptr] != 0) break;
for (++code_ptr; loop > 0 || code[code_ptr] != ']'; ++code_ptr) {
if (code[code_ptr] == '[') ++loop;
if (code[code_ptr] == ']') --loop;
}
break;
case ']':
if (buffer[buffer_ptr] == 0) break;
for (--code_ptr; loop > 0 || code[code_ptr] != '['; --code_ptr) {
if (code[code_ptr] == ']') ++loop;
if (code[code_ptr] == '[') --loop;
}
--code_ptr;
break;
}
}
return 0;
}



出力


h.bf

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

------------.<++++++++.--------.+++.------.--------.>+.


出力

$ brainc.exe h.bf

Hello, World!


他言語での実装

コンパイラ・インタプリタ、ともに載せています。

Rust >> brainf*ck

Javascript >> シラミ騒動で Brainf**k

D言語 >> D言語でBrainf

C# >> Brainf*ck .NET

Ruby >> Brainf*ck | RubyでBrainf*ckのコードを生成する

Ruby >> brainf*ckを書いてみた

JavaScript >> Node.jsでPEG.jsでBrainf*ck

C >> c言語でBrainf*ckインタプリタ

D >> D言語でBrainf*ckコンパイル時コンパイラを作ろう

JavaScript >> JavaScriptでBrainF*ckインタプリタを実装する

解説 >> 今すぐBrainf*ckを始めるべき10の理由


ソースコードのライセンス

These codes are licensed under CC0.

CC0

ソースコードは自由に使用してください。