« PerlでONS バイトコード私見2 | メイン | 魔法少女アイ2 plus コンバータ for ONScripter »

2007年12月30日

●PerlでONS バイトコード私見3で正規表現ものの…2

ある程度解析出来たらPerlスクリプトへ。

%0a%07%00%00%00%f4%01%0c%07%00%ec%ff%00%00%f4
%01%0a%08%00%00%00%ff%ff%04%08%00<23>%e6%00%00
%00...

で、太字部分は
『7番の画像を F4 01(500) m秒で EC FF (-20 ※1) だけ移動』
という命令だと解釈したとします。
これを中の数値が変動することを考えて正規表現で表すと

%0c%[0-9a-f][0-9a-f]%00%[0-9a-f][0-9a-f]%[0-9a-f][0-9a-f]%00%00%[0-9a-f][0-9a-f]%[0-9a-f][0-9a-f]※2

ついで前後に区切り記号※3を入れて置換してみる。

$line =~ s/(%0c%[0-9a-f][0-9a-f]%00%[0-9a-f][0-9a-f]%[0-9a-f][0-9a-f]%00%00%[0-9a-f][0-9a-f]%[0-9a-f][0-9a-f])/:$1:/g;

…と進めるわけですが、頭から処理するわけではなく全文に対して置換処理を行っているので
どうしても誤爆が出てしまいます。
例えば短い処理だと %02%[0-9a-f][0-9a-f]%00 だけで画像x番の消去という制御だったりします。
しかしこれを単に s/(%02%[0-9a-f][0-9a-f]%00)/:$1:/g; とすると、
%0c%02%00%00%14%00%00%f4%01 という先ほどの画像移動命令にもマッチし、結果

%0c
%02%00%00
%14%00%00%f4%01

という意味をなさない記述になってしまいます。
そこで正規表現のおまけに言語が付いているPerl※4の本領発揮、
正規表現の先読み・後読み機能を駆使して例外パターンを排除していきます。

詳しくはこちら様を参考に。


先読み (?=pattern)
s/(%02%[0-9a-f][0-9a-f]%00)(?=%02)/:$1:/g;
→ 後に%02がある %02%[0-9a-f][0-9a-f]%00

これを s/(%02%[0-9a-f][0-9a-f]%00)(%02)/:$1:$2/g; としてもそこでは同じ結果ですが、
%02%07%00%02%08%00 の様に連続している場合、次の処理が%08から始まりマッチしません。

否定的先読み (?!pattern)
s/(%02%[0-9a-f][0-9a-f]%00)(?!%02)/:$1:/g;
→ 同様に、後に%02がない同上

(?!%00)%[0-9a-f][0-9a-f] とすると、%00以外の%…となります。
マッチの位置が移動しないことに注意。これに限らず、ゼロ幅の~読みと言います。

後読み (?<=pattern) ※5
s/(?<=%0a)(%02%[0-9a-f][0-9a-f]%00)/:$1:/g;
→ 前に%0aがある %02%[0-9a-f][0-9a-f]%00

否定的後読み (?<!pattern) ※5
s/(?<!%0a)(%02%[0-9a-f][0-9a-f]%00)/:$1:/g;
→ 前に%0aがない %02%[0-9a-f][0-9a-f]%00

あとは、グルーピングによる "or" 処理もよく使います。
%(0a|0c) → %0aか%0cのどちらか
その際は (?:pattern1|pattern2) とすると後方参照が行われないのでPerlに優しいかも。

否定的後読みと組み合わせて
s/(?<!%0a|%0c)(%02%[0-9a-f][0-9a-f]%00)/:$1:/g; としたり。
日本語でおkだと 前に%0aも%0cもない%02…となります。

参考
/(?<=hoge)(?!hoge)(.+?)(?=hoge)/
この場合、『hogeに挟まれたhoge以外の文字列』がマッチして$1に入る


とまあ、バイナリを全文置換していくと畢竟こうした例外的なマッチングが増えるので、
解析がある程度終わった後は nsc.pl ※6 でのNスク化処理をしながら
誤爆で置換されていたりと使われなかった行をデバッグ用ファイルに書き出し、
同時にotbk.pl ※7 へ対処する置換処理を組み込んでやってました。

最終的には制御コード一つに対してこんな感じに(二例ですが)

$line =~ s/(?<!%1f%[0-9A-Fa-f][0-9A-Fa-f])(?<!%1f%[0-9A-Fa-f][0-9A-Fa-f]%[0-9A-Fa-f][0-9A-Fa-f])(?<!(?:%1e|%0a|%0c|%58|%bc|%ee))(%02%0[0-9A-Fa-f]%00)/:$1:/g;
$line =~ s/(?<!(?:%0a|%0c))((?:%07|%06)(?:%00%00%00|%ff%ff%ff|%00%f0%ff|%cc%00%00)(?!%00%00)%[0-9A-Fa-f][0-9A-Fa-f]%[0-9A-Fa-f][0-9A-Fa-f])/:$1:/g;

興味がある人はおとボクコンバータの otbk.pl 内サブルーチン parag ※8を覗いてみてください。
ちなみにアリスマの解析自体は大体終わっているのですが、バイトコードが一新されているので
全処理に対して改めて同様の置換を行う必要があったりあったりします。
気力が沸いたら手を付けようと…。SEVEN.NETを(略

このようにしてバイトコードの整形が終われば(というかほぼ並列ですが)、
後は吉里吉里などと同様に(まあ命令は読めませんが)Nスクへと移植処理をしていきます。

と、こんなあたりでgdgdで読みにくいバイトコード私見終了。
もしもご覧になられて何かしらの参考にして頂けたら望外の極みであります。※9

※1,リトルエンディアンで補数で符号が云々 0xEC - ( 256 - 0xFF ) * 256 = -20
※2,ハッシュでもある"%"はスカラコンテキスト中では評価されません。ほ
※3, @list = split(/:/,$data) で":"を区切りに配列化→改行付きで出力しています。
※4,あるあ…ねーよ
※5,現在の?Perlでは上記参考サイト様とは少し表記が違います。
※6,バイトコード形式のコンバータでは 似非ダンプスクリプトとNスク化スクリプトを分けています。
※7,おとボクの場合、otbk.pl が似非ダンプ、 nsc.pl でNスク化処理を。
※8,paragraphの略と思われる。いまいち実情にあってない。
※9,直訳するとありがとうございました。

トラックバックURL

このエントリーのトラックバックURL:
http://hitotsumori.com/x/cgi-bin/mt/mt-tb.cgi/73

コメントする