「*?」の実装(怠zyな「*」)コンビナトリアルGLRパーサーのregexpパターン

StackOverflow https://stackoverflow.com/questions/4365881

  •  09-10-2019
  •  | 
  •  

質問

組み合わせGLRパーサーを実装しました。その中には:

  • char(·) 指定された文字または文字の範囲を消費するパーサー。
  • many(·) 指定されたパーサーをゼロから無限の時間まで繰り返す組み合わせ。

例: "char('a').many()" 文字列を任意の数と一致させます "a"-s。

だが many(·) コンビネーターは貪欲ですので、例えば、 char('{') >> char('{') >> char('a'..'z').many() >> char('}') >> char('}') (どこ ">>" パーサーの連続チェーンです)全体を正常に消費します "{{foo}}some{{bar}}" ストリング。

の怠zyなバージョンを実装したい many(·) 前の例で使用されると、消費されます "{{foo}}" それだけ。どうやってやるの?

編集:

私はすべて混乱しているかもしれません。私のプログラムでは、パーサーは「ステップ」を受け入れ、「ステップ」の森を返す関数(またはC ++の観点から「ファンサー」)です。 「ステップ」はOKタイプ(パーサーが入力の一部を正常に消費したことを意味します)と失敗タイプ(パーサーにエラーが発生したことを意味します)です。より多くのタイプのステップがありますが、それらは補助です。

Parser = f(Step) -> Collection of TreeNodes of Steps.

だから私が入力を解析するとき、i:

  • 単純な事前定義されたパーサー関数を構成して、必要な文法を表す複雑なパーサー関数を取得します。

  • 入力から初期ステップを形成します。

  • 複雑なパーサー関数への最初のステップを示します。

  • 手順でtreenodをフィルターし、OKのみを残します(または、入力にエラーがあった場合、最小フェールSで)。

  • 残された手順から情報を収集します。

役に立ちましたか?

解決

正規表現を考慮してください <.*?> と入力 <a>bc<d>ef. 。これは見つかるはずです <a>, 、そして他の試合はありませんよね?

次に、正規表現を検討してください <.*?>e 同じ入力で。これは見つかるはずです <a>bc<d>e, 、 右?

これはジレンマをもたらします。ユーザーのために、コンビネーターの動作が必要です >> 2つのオペランドの観点から理解される。しかし、最初のパーサーの動作を最初に見つけたものに関して、2番目のパーサーの動作を作成する方法はありません。

1つの答えは、各パーサーがaを生成することです 順序 すべてのパーサーの順序付けられていないセットではなく、優先によって順序付けられたすべてのareのうち。貪欲なマッチングは、最長から最短にソートされた一致を返します。非グリーディ、最短から最長。

他のヒント

私は、プログラム変換システムの言語の最前線として15年間GLRパーサーを実装し、使用しています。

「組み合わせGLRパーサー」が何であるかわからないので、あなたの表記に不慣れなので、それを解釈する方法はよくわかりません。これはある種のカレー機能表記だと思いますか?私はあなたのコンビネーターのルールが、「char( 'a')」の端末文字の観点からグラマーを定義することと同等であると想像しています。

 char = "a" ;
 char = char "a" ;

実際、GLRパーサーは、すべての可能なareを生成します。 GLR解析の重要な洞察は、すべての可能な偏区の並列処理です。 「コンビネーター」が複数のareを提案できる場合(つまり、上記と同等の文法ルールを作成します)、実際にGLRパーサーに接続すると、すべてが試行され、タイルのプロダクションのシーケンスのみが試されます。テキストは生き残ります(すべての有効なパーセン、例えば、あいまいな解析を意味します)は生き残ります。

実際にGLRパーサーを実装している場合、すべての可能性のある分割のこのコレクションは非常に明確であるはずです。それがあなたが実装したものを示唆していないという事実は、GLRパーサーではありません。

他の解析技術と同様に、GLRパーサーによるエラー回復が可能です。私たちがしていることは、エラーのポイントの前にライブ分割のセットを保持することです。エラーが見つかった場合、私たちは(psuedo-parallelで、GLR解析機械が適切に曲がった場合にこれを簡単にする)を試します:a)問題のトークンを削除し、b)本質的に続くすべてのトークンを挿入する(x)ここで、xはライブ解析です。本質的に、トークンを削除するか、ライブパースで予想されるものを挿入します。次に、GLRパーサーを再び緩めます。有効な区画(例、修理)のみが生き残ります。現在のトークンを処理できない場合、トークン削除された削除されたストリームを処理するパーサーは生き残ります。最悪の場合、GLRパーサーエラーの回復は、すべてのトークンをEOFに捨てることになります。これの深刻な欠点は、GLRパーサーの実行時間がエラーを解析している間、かなり根本的に成長することです。 1つの場所に多くの場合、エラー回復時間は屋根を通過できます。

GLRパーサーは、入力のすべての可能な分割を生成しませんか?次に、あいまいさを解決することは、あなたが好む解析を選ぶことの問題です。それを行うために、私は、どのような組み合わせがそれらを生産したか、熱心または怠zyなものに従って、解析林の要素にラベルを付ける必要があると思います。 (一般的にすべての入力を見る前に、あいまいさを段階的に解決することはできません。)

(私の薄暗い記憶とGLR解析の曖昧な誤解に基づいたこの答え。

非グリーディの機能は、曖昧性の除去メカニズムにすぎません。一般化パーサー(結果を生成するために曖昧性を除去する必要がない)が本当にある場合、「非卵」は意味がありません。オペレーターが「非グリーディ」であるかどうかにかかわらず、同じ結果が返されます。

非グリーディの分離挙動は、一般化されたパーサーによって提供される結果の完全なセットに適用できます。左から右への作業により、非グリーディのオペレーターに対応する曖昧なサブグループをフィルタリングして、残りの入力の解析が成功した最短一致を使用します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top