Rustのマクロが面白かったのでBrainfuckの処理系を作ってしまった
タイトルの通りです
Rustのマクロを初めて触ったのですが、結構いろいろできそうでした(というかチューリング完全らしい)
条件付きですが自分で構文のパースもできるようで、これは何かできないかとおもったところで思いついたのがBrainfuckでした
Rustのマクロについては、こちらの記事がかなり詳細に書いてくださっているので構文などはこちらをご参照ください qiita.com
また、Brainfuckの仕様についてはWikipediaのものに従ったつもりです ja.wikipedia.org
コード
さて、私が書いたBrainfuckを処理するマクロがこちらです
3-43行がマクロの定義です 9パターンの分岐があります
まずいちばん上のパターンは最初に呼ばれ、メモリやポインタの定義を担当します
memory
という配列がBrainfuckが扱えるメモリ領域になります
2番目は一番最後に呼ばれ、処理内容をすべて処理し終わったときに該当し、何もしないという命令を返します
3番目以降で実際に命令を処理しています 慎重に見れば、一番前の命令のみパターンマッチし、2番目以降は再帰的に処理していることがわかると思います(1番下のみ例外)
46,47行目がこのマクロの呼び出し側です
このコードはABC
と出力するBrainfuckのコードです
コンパイル時にマクロによりRustのコードに置換され、コンパイルされます
問題点
このコードの問題点として、字句解析は基本的にRustのパーサ(トークナイザ?)が行うため、Rustの言語仕様で演算記号として定義されてる>>
などが正常に処理されません
間にスペースを入れれば正常に動くのですが、このあたりはできればもう少し柔軟にできればよかったですね
ちなみに、マクロの書き方を調べてたのは、これでパーサを定義できないかなとか考えてたからなんですけど、変数名等の識別子に関して自分で1文字ずつパースすることは同じ理由でできなさそうなので諦めました... マクロにBNF渡してパーサを定義するとかちょっと便利そうだったんですけどね 残念
追記
面白かったので>>と<<をサポートしてみた。https://t.co/AFkBatY4J4
— κeen (@blackenedgold) November 30, 2019
分割すればOK。あるいは>>が来たら2回moveでもいいけどね。https://t.co/7SEEtm6ewx
>>
や<<
は> >
や< <
に置換するようなルールを作れば対応できるという提案をいただいた
私のコードだと実は>>
や<<
以外にも->
等がエラーになりますが、同様に対応するルールを作れば対応できそう
(この方法でもやはりパーサの定義までは繋がりそうにないのが悲しいところ)