7

文法の出発点は次のとおりです。

%%{
  machine xo;

  char = "x" | "o";
  group = "(" char* ")";
  main := group;
}%%

(xxxx(oo)()xx)たとえば、 を処理します。ネストされたグループを許可するように拡張するにはどうすればよいですか。例えば(xxxx(o(x)o)()xx

通常、1 台の Ragel マシンでは再帰がサポートされないことはわかっています。したがって、これは機能しません:

group = "(" ( char | group )* ")";

Ragel State Machine Compiler User Guide (PDF)から: (強調のために太字のテキストを追加):

「一般に、Ragel は再帰構造を処理できません。これは、文法が通常の言語として解釈されるためです。ただし、何を解析する必要があるかによっては、手動コーディング手法を使用して再帰部分を実装することが実用的な場合があります。これは、再帰構造が括弧のバランスをとるなど、単純で認識しやすいです。」

「再帰構造を解析する 1 つのアプローチは、カウンターをインクリメントおよびデクリメントするアクションを使用するか、再帰構造への入り口と出口を認識し、fcall と fret を使用して適切なマシン定義にジャンプすることです。別の方法として、セマンティック条件を使用してカウンターをテストすることもできます。変数。

「より伝統的なアプローチは、再帰構造に入ったときに別の解析関数 (ホスト言語で表現された) を呼び出し、後で終了が認識されたときに戻ることです。」

ネストされたブラケットに関するメーリング リストのディスカッションから、同じ 3 つのアプローチが言及されています。

  1. prepush と postpop を使用して成長可能なスタックを指定してから、fcall と fret を使用します。

  2. カウントしてから、アクションまたは条件で確認します。

  3. 再帰構造に入ったときに、(ホスト言語で) 新しい解析関数を呼び出します。

できれば上記の例を使用して、Ruby でのそれぞれの例を教えてもらえますか? ありがとう!

4

3 に答える 3

10

fcall/fret を使用する一般的なパターンは次のようになります。

balanced = [^(){}\[\]] |
               '(' @{ fcall balancedTokensParen; } |
               '[' @{ fcall balancedTokensBracket; } |
               '{' @{ fcall balancedTokensBrace; };
balancedTokensParen   := balanced* ')' @{ fret; };
balancedTokensBracket := balanced* ']' @{ fret; };
balancedTokensBrace   := balanced* '}' @{ fret; };

したがって、あなたのケースは次のように処理できます

  char = [xo];
  group = '(' @{ fcall group_rest; };
  group_rest := (char|group)* ')' @{ fret; };

  main := group;

レクサー関数にはstack配列が含まれている必要がtopあり、閉じられていない「(」がないことを確認するために手動でチェックする必要があります。

stack = []
%% write init;
%% write exec;
if top > 0 
    cs = %%{ write error; }%%
end
于 2012-10-11T09:00:24.317 に答える
1

大まかに言えば、括弧を一致させようとしている場合、解決策には次のようなものが含まれます。

open_paren = '(' @{ @paren_count += 1}
close_paren = (')' when @paren_count > 0) @{ @parent_count -= 1}

セマンティック条件に関するユーザー ガイドの最後のセクションを確認してください。

余談ですが、Ragel は非常に強力なツールであり、実際に使用するにはその基盤を理解する必要があります。Ragel を使用するための最初のステップは、ユーザー ガイドを読んで理解することです。まだ不明な点がありますが、Ragel を使用するのは非常にイライラします。

于 2012-10-10T19:29:57.257 に答える
1

私もその Ragel 問題について何日も探していました!

Ragel は、再帰的な [ネストされた括弧] を渡すなどのニーズについて十分に文書化されていません。

5 日間の Google 検索で見つけた唯一のサンプル コードは次のとおりです。

https://bitbucket.org/mitsuhiko/arana-main/src/289ad1a6f083/arana/lexnparse.rl

Ragel スタックのニーズと、fgoto() [または fcall()]、fret()、およびそのようなことを行うために必要なその他のコード管理の Ragel コード オーバーヘッドを見て、私は (他の多くの人と同じように) Ragel はそのようなニーズのための簡単なツールではありません。それ以外の場合は、複数の実用的な例が利用可能になります。

于 2012-08-19T12:13:29.953 に答える