命令50個、ダイアログ実装完了!

kujirahand2007-02-24


葵ですが、ようやく命令が50個程度が動くようになりました!
モーダルダイアログも「言う」「尋ねる」「二択」の実装ができました。
それで右のようなダイアログが表示できるようになりました。

今のところファイルサイズも、本体10KB+ダイアログリソース10KBと合計20KB程度。
このくらいなら、携帯電話上のFlash Lite2でも軽快に動きそうな気がします。
(実際にやるには調整が必要そうですが...)
来月中旬には、ベータ版を公開できると思います。
お楽しみに。

Flash Liteの対応端末について、ちょうど質問があったので答えてみました。
http://q.hatena.ne.jp/1172261268

コンフリクト問題の詳細(コンフリクトしないで可決できるケース)

先日のコメントで、コンフリクトする場合の説明が足りませんでしたので、補足的に書いて再度解決策について考えて見ます。
以下のようなプログラムがうまくBNFで解決できないのではないかと指摘がありました。

●テスト(AとBを)
  それは「({A},{B})」

「A」と「B」と「C」をテストをテスト。
それを表示。

これを実行すると、正しく「(A,(B,C))」という結果が返ってきます。
これは、各トークンのつなぎ方を工夫しているために解決できています。
例えば、「引数1(と)→引数2(を)→関数(と,を)」とあったとき、以下のツリー状につなぎ直すようにしています。

+ - NOP
  | - 引数1(と)
  | - 引数2(を)
  | - 関数

文法的には以下のようになっています。

引数リスト : 引数
           | 引数リスト 引数
           ;
関数呼出   : 引数リスト 関数
           ;

関数呼出で、引数リストの中から必要な助詞だけをピックアップするようにして、残りは、引数リストに残しておきます。
そして、この後の関数呼出で、引数リストを再び調べます。
『「A」と「B」と「C」をテストをテスト。』は以下のように繋がり、正しく解析されます。

+ - NOP
  + - NOP
    | - A  (と)
    | - NOP(を)
    | + - NOP
    |   | - B (と)
    |   | - C (を)
    |   | - テスト
    | - テスト

コンフリクトしてしまうケース

それでコンフリクトするケースを考えてみると、例えば「今日&「_」&今を表示。」のようなケースです。
つまり、関数の引数の中に、関数があり、その関数が演算を行うような場合です。
現在、以下のように定義しているので、引数リストの中に関数を含ませたい場合は、関数をカッコで括って「(今日)&「_」&(今)を表示。」と書くと動きます。(文法定義の*1)

value       : variable
            | NUM                   { $$ = nc.constNum($1); }
            | INT                   { $$ = nc.constInt($1); }
            | STR                   { $$ = nc.constStr($1); }
            | '(' expr ')'          { $$ = nc.setJosi($2,$3); }
            | '(' callfunc ')'      { $$ = $1; } //-------------------(*1)
            ;
callfunc    : expr_list FUNC                { $$ = nc.callFunc($2, $1);   }
            | FUNC                          { $$ = nc.callFunc($1, null); }
            | FUNC '(' expr_list ')'        { $$ = nc.callFunc($1, $3); }
            ;

では、なぜ1つ前のケース(『「A」と「B」と「C」をテストをテスト。』)がうまく動くのかと言えば、引数リスト(expr_list)に関数呼び出しを書いているからです。構文解析にかける前に、引数となる関数をFUNCARGに置き換えているのです。

expr_list   : expr                  { $$ = nc.expr_list_top($1); }
            | FUNCARG               { $$ = nc.callFunc($1,null); }
            | expr_list expr        { $$ = nc.expr_list_next($1, $2); }
            | expr_list FUNCARG     { $$ = nc.callFunc($2, $1); }
            ;

次に、解決策を考えて見ます。

  • 方法1 : 関数呼び出し部分をあらかじめ見つけ、カッコで括ってしまう。
    • 「今日&「_」&今を表示。」を「(今日)&「_」&(今)を表示。」に変更する。
    • (長所)文法定義を変えなくて済む
    • (短所)非常に困難。関数呼出部分を見つけるのは簡単だが、関数呼出に対応する引数を見つけるのが難しい。
    • ★例外的に、関数の引数が0の場合のみカッコで括るのは簡単
  • 方法2 : 引数リスト(expr_list)の定義を工夫する
    • (長所)抜本的な解決である
    • (短所)コンフリクトの嵐と戦う(方法1より困難?)

とりあえず、方法1の★例外はすぐ実現できるので対策を行ってみます。