LR解析を使用した順列フレーズ


16

置換語句は、標準(E)BNF文脈自由文法定義の拡張である:置換語句含まNプロダクション(または同等に、非終端)スルー。順列句の位置で、これらの生成物のすべてを正確に1回ずつ見たいと思いますが、これらの非終端記号の順序には興味がありません。{A1,,An}nA nA1An

例えば:

S <- X { A, B, C } Y

と同等です:

S <- X  A B C  Y
S <- X  A C B  Y
S <- X  B A C  Y
S <- X  B C A  Y
S <- X  C A B  Y
S <- X  C B A  Y

この概念は、「順列句による文脈自由文法の拡張」で紹介されているようです。また、LL(1)パーサーを使用してこれらのフレーズを線形時間で解析する方法も説明されています。

「パーミュテーションフレーズの解析」という論文では、パーサーコンビネータを使用してパーミュテーションフレーズを解析する方法について説明しています。これらは、順列句とその解析方法について説明している唯一の2つの論文です。

これらの種類の置換句をLL(1)ベースのパーサーで簡単に解析できることを見て、LR(1)スタイルのパーサーでも同じことができると思います。したがって、私の質問は次のとおりです。

順列句を含む文法は、適切なサイズのテーブルを維持しながら、LR(1)機構を使用して入力文字列サイズで時間線形に解析できますか?

順列句は、文脈自由言語の能力を拡張するものではありません。上の例のように、考えられるすべての順列を単純に列挙できます。ただし、結果のグラマーのサイズはなる可能性があるため、グラマーは爆発します。これにより、線形時間解析が可能になりますが、文法のサイズが非常に大きくなります。O(|G|!)

O2|G|

これは優れていますが、もちろん十分ではありません。30項目の順列フレーズがあると、文法が使用できなくなります。まだ触れていないLR解析の一部があり、それが解析に使用される実際のスタックベースの手順です。スタックにカウンターを保存することで問題を解決できるかもしれないと思いますが、その方法はわかりません。

現在、パーサージェネレーターを実装していますが、問題の分野では、順列フレーズは天からの贈り物になるでしょう。LR(1)機械を使用しているので、上記の質問が続きました。


LR(1)構文解析の複雑さは、順列句のない文法のサイズですでに指数関数的です。ただし、パーサーの「オンザフライ」計算を実装する場合を除き、それは、Aerleyパーサーのように感じます。純正LR(1)1つ。
シルヴァン

2
あなたの質問の残りについて:cstheory.stackexchange.com/questions/4962/…は、順列のCFGのサイズの指数下限を示し、PDAからのCFGの通常の多項式構築により、これは指数下限を伴います。 PDAのサイズも同様です。
シルヴァン

1
私はLL(1)に関する論文を見ていませんでした。実際、実装されたパーサーはもはやPDAではありません。私はまだ「合理的なサイズのテーブル」の存在を信じていません。なぜなら、可換文脈自由文法のメンバーシップはNP完全であるからです(例えばdx.doi.org/10.3233/FI-1997-3112を参照)が、それは本当ですハードインスタンスがLR(1)ではない可能性があること。
シルヴァン

2
@Sylvain:質問4962がこの質問とどのように関係しているかについて詳しく説明してください 質問4962では、入力の長さごとに置換が固定されており、置換される文字列が変更されます。現在の質問では、順列を修正していません。したがって、それらの間の実際の接続を確認できません。
伊藤剛

2
@Tsuyoshito Ito:LR(1)の解析では、入力文法に相当するDPDAが最初に構築され、次に文字列に対して実行されて認識されます。すべての順列言語の順列フレーズを持つ線形サイズのCFGが存在するため、Yuval Filmusの論文(cstheoryについての彼の答えよりも包括的です:cs.toronto.edu/~yuvalf/CFG-LB.pdfを参照)は、このようなDPDAは、入力文法のサイズが多項式サイズである場合があります。
シルヴァン

回答:


1

これをセマンティック問題に変換することを検討しましたか?非終端記号{A、B、C}のすべての順列の文法規則の代わりに、(A | B | C)^ 3を認識するための1つの規則と、それぞれの1つだけが認識されるようにする特別な内部コードを用意します。エラー。上記の節の前に空のプロダクションを挿入します。その削減は、A、B、Cのカウントに使用しているものの初期化をトリガーし、その後、その削減がカウンターチェックをトリガーし、(必要に応じて)エラーをアサートします (もちろん、文法がA、B、および/またはCを介して再帰的である場合、これには少し注意が必要です)


0

カウンターは必要ないと思います。基本的には、すべての順列をチェックするだけで、壊れます

擬似コード:

perm-match(input, pattern)
     if pattern = nil return true

     foreach(rule in pattern)
         if (match(input, rule))
             perm-match(input - matchedpart, pattern - rule)
             break
         end
     end
     return false
end

より具体的な例を示します

abcdの任意の順列と一致させようとしており、文字列がbcdaであるとします

  • ステップ1:最初に一致したシンボルを見つけます。この場合、b
  • ステップ2:パターンからそのシンボルを削除し、文字列を減らします。たとえば、acdとcdaは残っています
  • 手順3:新しい文字列で手順1を繰り返します
    • cはcdaで一致し、adとdaが残ります。
    • aに一致すると、dとdが残ります
    • dはdに一致し、両方の文字列にnilが残ります。

したがって、この単純なアルゴリズムでは、「文字列」の順序を単純に比較するだけで、順列を簡単に確認できます。関数の複雑さはO(n!)の最悪の場合とO(1)の最良の場合であることに注意してください。ある意味では、配列に一致するシンボルを保存することでカウントを維持しています。ほとんどの場合、非常に大きなnを処理しないため、これは一般に「高速」になると思います。


2
nn=50
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.