コメント_2019-05-20_061415

wasm用のプリプロセッサ(mwasm)をnode.jsで作っている

動機

WASMが出てきて、WASMを吐くコンパイラが作れそうだったので「オレオレ言語」を去年の2月くらいから作っていた。今はちょっとお休みの状態になっている。プリプロセスをどうしようかというところで手が止まってしまったのだ。複雑なプリプロセッサ+メタ・プログラミング機能を追加しようとして実装をどうしようか迷っているうちにモチベーションが萎えてしまった。身の丈に合わない仕様を思いついたんだけど私の実装能力が低いから先が見えなくなったのだ。binaryenの助けを借りながら、WASMバイナリを吐くとことまではできたんだけどね。

オレオレ言語を作っている

趣味というのは「締め切り」がないし、やめようと思えばいつでもやめれるので、完成させるまでのモチベーション維持が難しいなあと常々思っている。なので過去いろいろな成果物にトライしているものの、完成できずに放置しているものがいくつもある。はあ。。

しばらくして、WASMのテキスト・フォーマットでPSGエミュレータを作りたくなってきた。コードを書いてみるとメモリ・オフセットのラベリングができないちょっと不便というかわかりにくいなあ..と思った。

(module
 (memory $memory 1 )
 (export "memory" (memory $memory))
 (func $test 
   (i32.load (i32.const 1024 ));; <-- わかりにくい。
   .
   .

 )
)

「オフセットの1024バイト目はPSGレジスタの値だったよな、あれ違った。。」みたいな感じになるのはちょっとイライラする。

条件付きインクルードやソース・インクルードも必要そうなので、自分でプリプロセス部分を作ってみようと思ったのだ。このプリプロセスはオレオレ言語にも応用できそうだしね。wabtでwasmバイナリにできるから私でも作れそうかなあとも思ったしね。

それで以下のレポジトリを作ってちょこちょこ作ってみることにした。とりあえず継続して作業はできている。devリポジトリでいろいろ試して動くようになったらmasterにマージする感じで進めている。

https://github.com/sfpgmr/mwasm

どんな風なのか

作成途中であるので、不具合やおかしなところはたくさんあるだろうけど。。

メモリオフセットにラベルを付ける

以下のような感じで、メモリオフセットの定義・利用を行う。

(module
 (memory $memory 1 )
 (export "memory" (memory $memory))
 ;; メモリラベルの定義
 ;; 
 {@map
   i32 output;(;; 0バイト目 ;;)
   i32 input;(;; 4バイト目 ;;)
 }
 (func $test 
   (i32.load (&input;)) ;;メモリ・ラベルの利用 
   .
   .
 )
)

@mapディレクティブで型とラベル名を定義すると、メモリの先頭番地からのオフセットを計算してくれる。
これをプリプロセッサで処理すると、以下のwatに変換される

(module
 (memory $memory 1 )
 (export "memory" (memory $memory))
 (func $test 
   (i32.load (i32.const 4)) ;; <-- メモリオフセットに置換
   .
   .
 )
)

なんか記法がいまいちだけどね。

プリプロセスのコードはJSで書く

プリプロセスを書くメタ言語はJSにしてる。JSにはFunctionオブジェクトで実行時に関数オブジェクトを作って実行できる機能があって、これ使うとプリプロセスをJSに任せて実装を端折れるので。

{@
 $.X = 1;
 $.Y = 2;
}
(module
 (func $test2 (result i32)
   i32.const @X;; comment
   i32.const {$ $.X + $.Y }
   i32.add
   {
     // JSによるWASMソースコード生成
     let instructions = '';
     for(let i = 0;i < 4; ++ i ){
       ++$.X; 
       instructions += `
 i32.const ${$.X + $.Y}
 i32.add`;
     }
     return instructions;
   }
 )
)

このソースのプリプロセス後のwatは以下になる。

(module 
   (func $test2 (result i32) 
    i32.const 1
    i32.const 3
    i32.add 
    i32.const 4
    i32.add
    i32.const 5
    i32.add
    i32.const 6
    i32.add
    i32.const 7
    i32.add 
   )
)

使いどころはそこそこあるんじゃないのかなあと思ってるんだけどね。

あとソース・インクルードとか条件分岐とかもできるようにしてる。

今後

とりあえず以下のPSG(Programmable Sound Generator)のエミュレータコードを書いてみて動かそうと思ってるところ。
PSGエミュレータ・コードは以下のCソースを参考にしている。というかそれをまんまwatに書き直そうとしている。
https://github.com/digital-sound-antiques/emu2149

実際のコードを書きながら進めれば足りないところがよくわかるので機能を付け足してくつもり。それができればちょっとゲームを作ってみたいんだよね。そこまでできればまあとりあえずは使えるレベルかどうかわかるかどうかがわかる。

あとは今の文法はなんか行き当たりばったりな感じなのでひょっとしたら見直すかもしれない。



この記事が気に入ったらサポートをしてみませんか?