なぜつくったのか
r-fxxkという、Brainfuck派生言語を簡単に作成するためのRubyライブラリがあります。たとえば、プログラミング言語フレンズ Kemonoは以下のような非常に簡単なコードで実装されています。
class Kemono < Brainfuck
nxt "たのしー!"
inc "たーのしー!"
prv "すごーい!"
dec "すっごーい!"
opn "うわー!"
cls "わーい!"
put "なにこれなにこれ!"
get "おもしろーい!"
end
PHPにも似たようなのが無いかなー、と思って探してみましたが、見つからなかったので作りました。コードはGitHubで公開しています。
つかいかた
インストール:
composer require ryo-utsunomiya/php-fxxk
Kemonoを実装してみます。
<?php
require_once __DIR__ . '/vendor/autoload.php';
use BrainFuck\Mapping;
use BrainFuck\Language;
// Kemono の定義
$kemono = new Mapping([
'たのしー!',
'たーのしー!',
'すごーい!',
'すっごーい!',
'うわー!',
'わーい!',
'なにこれなにこれ!',
'おもしろーい!',
]);
// 「Hello World!」を出力するプログラムを生成
$program = $kemono->helloWorld();
echo $program . PHP_EOL;
// マッピングを使用してプログラム実行
$output = Language::withMapping($kemono)->run($program);
// プログラムの実行結果はintの配列になるので、
// intをasciiの値とみなして文字列として出力
foreach ($output as $char) {
echo chr($char);
}
ちなみに、KemonoでHello World!を出力するプログラムは以下。
すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!なにこれなにこれ!たのしー!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!たのしー!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!たのしー!すごーい!すごーい!すごーい!たのしー!すごーい!たーのしー!たーのしー!たーのしー!たーのしー!すっごーい!おもしろーい!たのしー!すごーい!すごーい!うわー!たのしー!すごーい!うわー!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!うわー!うわー!すごーい!すごーい!すごーい!うわー!たのしー!すごーい!すごーい!うわー!たーのしー!たーのしー!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!すごーい!うわー!たのしー!うわー!すごーい!すごーい!すごーい!うわー!すっごーい!すっごーい!すっごーい!すっごーい!すっごーい!すっごーい!うわー!すっごーい!すっごーい!すっごーい!すっごーい!すっごーい!すっごーい!すっごーい!すっごーい!うわー!たのしー!すごーい!うわー!たのしー!うわー!
Mapping
を継承したクラスを作ってもOKです。
<?php
namespace KemonoFriends;
use BrainFuck\Mapping;
class Kemono extends Mapping
{
protected $mapping = [
'たのしー!',
'たーのしー!',
'すごーい!',
'すっごーい!',
'うわー!',
'わーい!',
'なにこれなにこれ!',
'おもしろーい!',
];
}
設計のポイント
BF系言語を翻訳して本家Brainfuckに変換し、Brainfuckインタープリタが変換後のコードを実行する、というのがこのライブラリのアーキテクチャです。
このライブラリにおいてキモになるのは、BF系言語 => Brainfuckの変換部分で、ここはMapping
というクラスが担っています。
PHPで実装されたBrainfuckのインタープリタはいくつかありますが、ircmaxell/PHP-BrainFuckを使っています。クラスがきれいに分割されていて、拡張しやすそうだったので採用しました。
まなんだこと
当初は、スクラッチでBrainfuckインタープリタを作ろうとしてたのですが、意外と大変でした。特にループが難しく、プログラム中からループの内部だけを正規表現で抜き出そうとすると、コードのトークンが2文字程度でもバックトラック制限に引っかかります。
そこでr-fxxk等の実装を眺めてみたところ、インタープリタの部分はBrainfuckのままで、変換部分で工夫している、ということが分かったので、同じように実装しました。
あと、Packagistにライブラリを公開するのは初めてだったんですが、ソースがGitHubにあってcomposer.jsonに必要な情報が書いてあれば、簡単に公開できるということがわかりました。