■ 新・ゲーム開発講座 |
■ へっぽこプログラミング入門♪ |
■第28夜:ラベルとジャンプ フラグ、分岐、と来たところで次に欲しい機能は何でしょう。#if_flag
によって処理を分岐することは出来ましたが、いくらネスト記述が出来るからといって、複雑な括弧の応酬が繰り返されたのではスクリプトが見づらくなってしまいますよね。分岐したらなるべく早い段階で
#if_flag 文のテキストブロックの呪縛?から逃れて、別の場所にジャンプできると便利です。そんな訳で、ここではラベルジャンプについて解説します。コマンドとしての書式は以下のようなものに致しましょう。
「ラベル」というのは直訳すれば「張り紙」ですが、要するに目印のことです。#jump コマンドは、この目印をスクリプトファイルの先頭から順次サーチして、該当するものがあったらその位置の直後にテキストポインタを移動します。ポインタの移動なんてものは1行で済んでしまいますので、今回のミソはラベルのサーチにあると言えるでしょう。 ■サーチ サーチと言っても、データベースを木構造で探索するような高度なものではありません。単純にファイル先頭から「ラベルはないか〜?」と1バイトずつ比較して探していく芸のないやりかたです。ただしレベル1のワザでも「使えない」「思い浮かばない」ことに比べたら天と地ほどの差があります。たとえ「へっぽこ」でも、勇気をもって力強く生きていきましょう(爆) 連続する文字列の中から特定の文字列(ラベル)を抽出する一番簡単な方法は、ラベル自身の「先頭文字」と「終端文字」を特定してしまうことです。終端文字の代わりに「必ずスペースが入る」でも良いのですが、たまたま文章中の特定の記述に引っかかって誤サーチになる恐れもありますので、ここでは明示的に「:」を終端に入れて区別できるようにしています。 サーチの基本アルゴリズムは単純です。スクリプトファイルの先頭から「*」を探してひたすら1バイトずつ比較をしていきます。「*」がみつかったら、32文字を限度としてその先に「 : 」がないかどうか探して、「 *なんとか: 」 の形式が成立していたらラベルとみなして比較をします。合致したらテキストポインタを書き換え、合致しなければ次を探します。 さて、そうは言っても次のような場合はどうしましょう。先頭から単純にサーチするだけでは、#jump *AAA:(=ジャンプ元の自分自身)のところでヒット扱いになっておかしな動作になってしまいます。さらにこのラベルにジャンプしてくる処理は、1本のスクリプトファイルに何回も出てくるかも知れません。 |
#if_flag 0 {
/
} いろいろな処理3 *AAA: |
そんな理由もあって、【ラベルの定義】では「行頭にあるラベルのみがジャンプ先として有効である」と規定してあるのです。「行頭」という条件を付ければ、ラベルの直前にあるのは1段上の行の改行コードか、インデント用のタブまたはスペースということになりますので区別ができます。これで少なくとも #jump *AAA: のようにコマンドパラメータとして記述してあるラベル文字列は除外できます。まあ、序論はこのくらいにして実際のコードを見ていきましょう。 ■Mode_stat ■コマンド解釈部 TextEngine.cpp の void Command_call() に以下の部分を加えます。 |
void Command_call() {
} |
■コマンド実行部 コマンド実行部は以下のようになります。ちょっとややこしいループ構造になってしまったため、条件が適合した場合のループ抜けに禁断?の goto を使っていますが、まあ気にしないで行きましょう。 |
int Com_jump() {
OUTLOOP:
} |
ラベルサーチ部分で、行頭チェックをしている部分に if( TEXT_BUF - (unsigned char*)(ptr+j) > 0 )・・・という記述がありますが、これは「前の行末が見つかれば」式に行頭チェックをしていると、スクリプトファイルの一番最初の行にラベルがあった場合に拾えなくなってしまうための苦肉の策です(^^;)。ポインタ同士を引き算するとメモリ間の距離が得られますので、その符号をチェックすることで前後関係を知ることができます。ラベルの直前に何があるかチェックしようとしてさかのぼったらテキストバッファの先頭を通り越してしまった・・・という場合のみ、「最初の行にラベルが記述してある」という評価を行う訳です。 ■ラベルは、見えてはいけない ラベルはジャンプ先を現わす単なる目印ですから、テキスト表示上は無視するようにしましょう。そんな訳で、制御文字チェックを担当している TextEngine.cpp の Check_control_chr() を少し拡張します。「*」を見つけたところで、空白を挟まずに32文字以内に「:」があればラベルとみなしてテキストポインタを飛ばしています。 |
int Check_control_chr()
{
} |
では、サンプルソースをコンパイルして実行してみて下さい。スクリプトファイル default.txt の内容と実際の表示を比較すると、ラベルジャンプの動作状況が良く分かると思います。 |