2006/4/10

エラー個所が表示されないのは何故?  VRMスクリプト禅問答
【怎麼生】
そもそもこのケースにおいて、未定義メソッドが含まれる部品・行がエラーメッセージに表示されないのは何故なんでしょうか?

【説破】 4.0.3.4
以下は、ボクちゃんの勝手な想像なので、VRM4の実装とは異なる部分があるかも知れませんが。


マニュアルを素直に読む限り、VRMスクリプトはビュワー起動時に「コンパイル」されているそうです。これは、プログラムによる解釈を経て、なんらかの別の形式に改められていることを意味します。
そもそもVRM4スクリプトの言語構造自体は、高速処理に向いたそれではなく、人間にとって理解しやすいスタイルを採用しています。「コンパイル」とは、そのままでは高速に処理するのが困難で、ビュワーに求められるリアルタイム処理を阻害しかねないスクリプトを、高速処理可能な内部形式へ変換する手順を指しています。また、この段階でスクリプト構文の誤りや書き間違えを弾くことで、ビュワーが予期せぬ異常動作することを予防する意味合いもあると思われます。

さて。
話を「メソッド」に絞って考えていくことにしましょう。VRM4スクリプトでは、異なるオブジェクトに書かれた同名のメソッドは、中身がまったくことなるものであってもそのまま実行されます。また、レイアウト内に1つでも名前が一致するメソッドがあれば、実際にコールされるオブジェクトに当該のメソッドがなくても、処理が空振りするだけでビュワーが異常終了したりすることはありません。ここから考えられることは・・・

(1) レイアウトの中で、メソッドの名前と内部処理形式のメソッドID(と仮に呼ぶ)が一対一対応する。
(2) オブジェクトのメソッドをcallするというのは、そのオブジェクトに「メソッドIDに対応した処理を実行せよ」と命じることである。
(3) レイアウト内のメソッドIDはユニークなので、対応する処理を持たないオブジェクトをコールしても何もせずに処理が正常終了する。
(4) この対応関係を確立するためには、コンパイル時にレイアウト内のユニークなメソッド名を洗い出し、それぞれにメソッドIDを割り当てる処理が必要となる。

です。
VRM4に、系統毎にユニークな番号を連番で発番する共用サブルーチンが含まれていることはほぼ間違いありません。部品番号や、最近ちょっと実験してみてわかったのですが、イベントハンドラに利用されるIDも同じ動きをしています。メソッドや変数の内部処理も、同様におこなわれていると考えることは妥当でしょう。

で、問題になるのは(4)の部分なんですが、これには大雑把に考えて二通りの解き方がありえます。

(a) レイアウト内のBeginFunc〜EndFuncを全部調べてメソッド名の一覧を得て、そこからユニークなメソッド名を抽出しメソッドIDを割り当てる。その後、call/SetEvent系命令に連なるメソッド名をメソッドIDに置き換える。
(b) レイアウト内のcall/SetEvent系命令を全部調べてメソッド名の一覧を得た、そこからユニークなメソッド名を抽出しメソッドIDを割り当てる。その後、BeginFunc〜EndFuncのメソッド名をメソッドIDに置き換える。

おそらく、VRM4が採用しているのは(b)なのではないか、というのが私の推理です。
(b)の場合、call/SetEvent系命令に連なるメソッド名に対応するメソッドがないことが判明するのは、VRMコンパイラが問題のcall/SetEvent系命令に注目しているときではなく、その処理によってメソッドIDが採番された次の段階として、レイアウト内のBeginFunc〜EndFuncを洗いざらい調べてみたところ、一度も使われないメソッドIDが残ってしまった(そのメソッドIDを実行するぞ、と書いてあるのに対応するメソッドがないことがわかった)瞬間です。
この時点では、VRM4コンパイラが注目しているのはユニークなメソッドIDの一覧とBeginFunc〜EndFuncで括られたメソッド構造であり、存在しないメソッドを実行しようとしたcall/SetEvent系命令の所在ではありませんから、エラー表示しようにもコンパイラ自身が既にそれがどこにあったかわかりません。
これを喩え話に変換すると、一堂に介した10人の友人からジュースの注文を取って近所の自動販売機に買いに行ったけれども、リクエストにあった中でメッコールだけがなかったと。で、買って帰りさえすれば本人が自分のリクエストするものを取ると考えていたので、その時点ではメッコールを欲しがっていたのが誰だかわからない。そんな感じ。誰だよ、メッコールなんか欲しがるヤツは。

逆に(a)の方法を取ればそれがわかるはず(先の喩えで言うならば、事前に最寄の自動販売機で商品の一覧を取得してから友人に注文を取って回るに相当、売ってないジュースの名前が友人の口から出た瞬間に「オマエの欲するメソッドはない」と言える)なのですが、(b)の方法には「一度も実行されないメソッドはコンパイルせずに済む(注文されていないジュースを探す必要はない)=メモリ節約・速度向上につながる」という利点があるので、それで(b)の方法を採用してるんじゃないないか、と。なにはさておき、リアルタイム処理が最優先されるVRMではさもありなん、と思うワケです。

仮にこの推理が正しいとして、一度も使われないメソッドIDが残った時点で、改めてレイアウト内の全スクリプトに検索をかけて、残ってしまったメソッドIDに対応するメソッド名が連なっているcall/SetEvent系命令を見つければ、エラー個所がわかるはずなんですが、VRMはそういう風になってないみたいです。
「手抜き!!」と言いたくなるところですが、上に書いた処理は本質的にはVRMの動作に必要がない「開発環境」に関わるものだからではないか、と思います。
一般的に、プログラマーという人種は、ユーザーが自力で実現出来ないであろうことを実現するプログラム(ここではコンパイラ)を書くことには情熱を燃やしますが、ユーザーがその気にさえなれば人力で解決できること(ここでは誤字脱字の発見)を援助するプログラムを書くことにはあまり関心を示さないと言うか、有り体に言えば「それぐらい自分で探せ」と言っちゃう傾向がありますので、まぁ、そんなもんじゃないか、と。

っつーか、ボクも同じものを作るとしたら、間違いなく同じようにしますから、「手抜き」だなんてとても言えません

皆さんには言う権利があります、どうぞ
0

コメントを書く

この記事にはコメントを投稿できません




teacup.ブログ “AutoPage”
AutoPage最新お知らせ