web-dev-qa-db-ja.com

LALRとLR解析の違いは何ですか?

LRとLALRの両方がボトムアップ解析アルゴリズムであることを理解していますが、2つの違いは何ですか?

LR(0)、LALR(1)、およびLR(1)の解析の違いは何ですか?文法がLR(0)、LALR(1)、またはLR(1)であるかどうかを確認するにはどうすればよいですか?

36
AAB

高レベルでは、LR(0)、LALR(1)、およびLR(1)の違いは次のとおりです。

  • LALR(1)パーサーは、より正確な情報を追跡して文法を明確にするLR(0)パーサーの「アップグレードされた」バージョンです。 LR(1)パーサーは、LALR(1)パーサーよりもさらに正確な情報を追跡する非常に強力なパーサーです。

  • LALR(1)パーサーはLR(0)パーサーよりも定数係数が大きく、LR(1)パーサーは通常、LALR(1)パーサーよりも指数関数的に大きくなります。

  • LR(0)パーサーで構文解析できる文法は、LALR(1)パーサーで構文解析でき、LALR(1)パーサーで構文解析できる文法は、LR(1)パーサーで構文解析できます。 LALR(1)であるがLR(0)ではなく、LR(1)であるがLALR(1)ではない文法があります。

より正式には、LR(k)パーサーは、端末と非端末のスタックを維持することによって機能するボトムアップパーサーです。パーサーは有限オートマトンによって制御され、パーサーの現在の状態と入力の次のkトークンに基づいて、新しいshiftかどうかを決定しますトークンをスタックに追加するか、プロダクションを逆に適用してスタックのトップシンボルをreduceします。

シフトするか減らすかを決定するのに十分な情報を追跡するために、LR(k)パーサーは、各状態を「構成セット」に対応させます。これは、次の情報で注釈が付けられたプロダクションのセットです。

  • これまでにどれだけの作品が見られたか、そして
  • 生成が完了した後に期待するトークン(lookahead

これらの情報の最初の部分は、パーサーが削減を行う必要があるかどうかを判断するために使用されます。現在の状態のプロダクションがどれも完了していない場合、削減を行う理由はありません。これらの情報の2番目の情報は、削減を行うときに、削減を実行する必要があるかどうかを判断するために使用されます。削減するかどうかを決定するとき、LR(k)パーサーは入力ストリームの次のk個のトークンを調べます。それらが先読みトークンと一致する場合、パーサーは削減し、それ以外の場合、パーサーは何もしません。

LR(k)パーサーで問題が発生するのは、特定の状態でパーサーが何を実行する必要があるかについて競合が発生した場合です。競合の1つのタイプであるshift/reduce競合は、パーサーがプロダクションが完了した状態にあるときに表示されますが、先読み記号はその生産の矛盾は、州内の別の未完成の生産でも使用されます。これは、パーサーがリダクションを実行するかどうかを判断できないことを意味します。 2番目のタイプの競合はreduce/reduce conflictで、パーサーは削減を行う必要があることを認識していますが、2つ以上の削減が可能であり、どちらをするべきかわかりません。

直感的には、kがどんどん大きくなるにつれて、パーサーは、シフトするタイミングと削減するタイミングを決定するために利用できるますます正確な情報を入手できます。たとえば、文法がLR(0)でない場合、パーサーは先読みがまったく与えられていない状態になっている可能性があり、シフトするか削減するかを決定できません。ただし、その文法はLR(1)である可能性があります。先読みの追加のトークンが与えられると、確実にシフトして削減せず、または確実に削減してシフトしないことを認識できる場合があるためです。

LR(k)パーサーの問題は、kが大きくなると、状態数が指数関数的に増加する可能性があることです。 LR(k)パーサーの先読みは、生成と先読みのさまざまな組み合わせに対応するようにパーサー内の状態を構築することによって処理されます。その結果、可能な先読みの数が増えると、状態の数も増えます。その結果、LR(1)パーサーは一般的に大きすぎて実用的ではなく、LR(2)以上は実際にはほとんど前例がありません。

LALR(1)は、LR(0)パーサーのスペース効率とLR(1)パーサーの表現力との間の妥協案として発明されました。 LALR(1)パーサーとは何かを考える方法はいくつかあります。元々、LALR(1)パーサーは、LR(1)オートマトンを小さなオートマトンに変換する変換として指定されていました。 LR(1)パーサーはLR(0)オートマトンよりも多くの状態を持つことができますが、唯一の違いは、LR(1)パーサーがLR(0)オートマトンに特定の状態の複数のコピーを持ち、それぞれに注釈が付けられることです。異なる先読み情報。 LALR(1)パーサーは、LR(1)パーサーから始めて、同じ「コア」を持つすべての状態(プロダクションとその位置のセット)を組み合わせて、すべての先読み情報をまとめることによって形成できます。これにより、パーサーはLR(0)パーサーと同じ数の状態になりますが、LRの競合を回避するために先読みに関する情報を保持します。

LALR(1)文法の別のビューでは、「LALR-by-SLR」方式を使用しています。 LALR(1)パーサーは、文法のLR(0)パーサーから始めて、対応するLR(0)パーサーの状態に関する情報で非終端記号に注釈を付ける言語の新しい文法を作成することによって構築できます。次に、その文法の非終端記号のFOLLOWセットに関する情報を使用して、LR(0)パーサーの先読みを計算できます。

最終的な結果は

  • LR(0)パーサーは小さいですが、あまり表現力がありません。
  • LALR(1)パーサーは、先読み情報のために少し大きくなりますが、非常に表現力があります。
  • LR(1)パーサーは巨大ですが、非常に表現力があります。

2番目の質問について-文法がLR(1)かLALR(1)かをどのように判断しますか-標準的なアプローチは、LR(1)パーサーとLALR(1)パーサーの解析オートマトンを構築してチェックすることです紛争のため。 LR(1)パーサーを作成するには、LR(1)構成セットを作成し、これらの構成セットのいずれかにシフト/削減の競合または削減/削減の競合があるかどうかを確認します。 LALR(1)パーサーを構築するには、LR(1)パーサーを作成してから、同じコアで構成セットを圧縮するか、言語のLR(0)パーサーに基づいてLALR-by-SLRメソッドを使用します。これらの構成セットを構築する方法の詳細は、ほとんどのコンパイラの教科書に記載されています。また、上記の解析方法のすべてと他のいくつかをカバーする 2012年夏に私が教えたコンパイラーコースの講義ノート も確認できます。

お役に立てれば!

58
templatetypedef

優れたLALR(1)パーサーの解析アルゴリズムは、次の2つの点で異なります。(1)シフト削減アクションが必要です。これにより、状態数が約30%削減され、パーサーが高速になります。(2)構文エラーを検出するときに1つ以上の削減を行うと、エラー回復がより複雑になります。

正規LR(1)パーサーの解析アルゴリズムには、(1)シフト削減アクションがなく、(2)構文エラーの検出時に削減が行われないため、エラー回復がより簡単になります。

LALR(1)と同じ解析アルゴリズムとエラー回復アルゴリズムを使用する、最小LR(1)と呼ばれる別のケースがあります。最小限のLR(1)パーサーはLR(1)の機能を提供し、そのサイズはLALR(1)とほとんど同じです。 LRSTAR Parser Generator は、C++プログラマー用の最小限のLR(1)パーサーを作成します。

1
user1524750

LR(0)、SLR(1)、LALR(1)パーサーはすべて同じ数の状態を持っています。最小限のLR(1)パーサーは、文法がそれを必要とする場合、reduce-reduce競合を回避するために、さらにいくつかの状態を持ちます。

Canonical LR(1)パーサーにはさらに多くの状態があり、中規模または大規模のコンピューター言語には多すぎます。

SLR(1)パーサージェネレーターはLR(0)ステートマシンを構築し、文法を調べることによってk = 1先読みを決定します(誤った競合を報告する可能性があります)。

LALR(1)パーサージェネレーターはLR(0)ステートマシンを構築し、(非常に複雑な)LR(0)ステートマシンを調べてk = 1先読みを決定します。

Canonical LR(1)パーサージェネレーターは、LR(1)ステートマシンを構築します。

最小限のLR(1)パーサージェネレーターは、LR(1)ステートマシンを構築し、ビルドプロセス中に互換性のある状態をマージします。

0
user1524750