SLR、LALR、およびLRパーサーはすべて、まったく同じテーブル駆動機構を使用して実装できます。
基本的に、解析アルゴリズムは次の入力トークンTを収集し、現在の状態S(および関連する先読み、GOTO、および削減テーブル)を調べて、何をすべきかを決定します。
- SHIFT:現在のテーブルがトークンTをSHIFTするように指示すると、ペア(S、T)が解析スタックにプッシュされ、GOTOテーブルが現在のトークンに対して言っていること(GOTO(T)など)に従って状態が変更されます。 )、別の入力トークンT 'がフェッチされ、プロセスが繰り返されます
- 削減:すべての状態には0、1、または状態で発生する可能性のある多くの可能な削減があります。パーサーがLRまたはLALRの場合、トークンは、状態のすべての有効な削減について先読みセットに対してチェックされます。トークンが文法規則G = R1 R2 .. Rnの削減の先読みセットと一致する場合、スタックの削減とシフトが発生します。Gのセマンティックアクションが呼び出され、スタックが(Rnから)n回ポップされ、ペア( S、G)がスタックにプッシュされ、新しい状態S 'がGOTO(G)に設定され、同じトークンTでサイクルが繰り返されます。パーサーがSLRパーサーの場合、最大で1つの削減ルールがあります。状態など、どの削減が適用されるかを検索することなく、削減アクションを盲目的に実行できます。SLRパーサーが存在するかどうかを知るのに役立ちます削減かどうか。これは、各状態がそれに関連付けられた削減の数を明示的に記録しているかどうかを簡単に判断でき、その数は実際のL(AL)Rバージョンに必要です。
- エラー:SHIFTもREDUCEもできない場合、構文エラーが宣言されます。
では、それらすべてが同じ機械を使用しているとしたら、何が重要なのでしょうか。
SLRで意図されている値は、実装が単純であることです。ルックアヘッドセットは1つしか存在しないため、可能な削減をチェックしてスキャンする必要はありません。これは、状態からのSHIFT出口がない場合に実行可能な唯一のアクションです。どの削減が適用されるかは、特に州に関連付けることができるため、SLR解析機械はそれを探す必要がありません。実際には、L(AL)Rパーサーは有用なより多くの言語のセットを処理し、学術的な演習以外には誰もSLRを実装しないほど実装する余分な作業はほとんどありません。
LALRとLRの違いは、テーブルジェネレーターと関係があります。。LRパーサージェネレーターは、特定の状態からのすべての可能な削減とそれらの正確な先読みセットを追跡します。最終的に、すべての削減が左側のコンテキストからの正確な先読みセットに関連付けられた状態になります。これは、かなり大きな状態のセットを構築する傾向があります。LALRパーサージェネレーターは、GOTOテーブルと縮約用のルックヘッドセットに互換性があり、競合しない場合、状態を組み合わせてもかまいません。これは、LRが区別できる特定のシンボルシーケンスを区別できないという犠牲を払って、かなり少ない数の状態を生成します。したがって、LRパーサーはLALRパーサーよりも多くの言語セットを解析できますが、非常に大きなパーサーテーブルがあります。実際には、ステートマシンのサイズを最適化する価値があるターゲット言語に十分近いLALR文法を見つけることができます。
つまり:3つすべてが同じ機械を使用します。SLRは、機械のごく一部を無視できるという意味で「簡単」ですが、問題を起こすだけの価値はありません。LRはより幅広い言語セットを解析しますが、状態テーブルはかなり大きくなる傾向があります。LALRは実用的な選択肢です。
以上のことをすべて述べた上で、GLRパーサーは、より複雑な機構を使用して、まったく同じテーブル(LALRで使用される小さいバージョンを含む)を使用して、コンテキストフリー言語を解析できることを知っておく価値があります。つまり、GLRはLR、LALR、SLRよりも厳密に強力です。標準のBNF文法を記述できれば、GLRはそれに従って構文解析します。機構の違いは、GOTOテーブルと先読みセットの間に競合がある場合、GLRが複数の解析を喜んで試行することです。(GLRがこれを効率的に行う方法は、まさに天才です(私のものではありません)が、このSOポストには適合しません)。
それは私にとって非常に役立つ事実です。私はプログラムアナライザーをビルドし、コードトランスフォーマーとパーサーは必要ですが、「面白くない」です。興味深い作業は、解析された結果を使用して行うことなので、解析後の作業を行うことに焦点が当てられています。GLRを使用すると、文法をハッキングしてLALRの使用可能な形式にするよりも、実用的な文法を比較的簡単に作成できます。これは、C ++やFortranなどの非アカデミックな言語に対処しようとするときに非常に重要です。C++やFortranは、言語全体を適切に処理するために文字通り何千ものルールを必要とし、文法ルールをハックしようとして人生を費やしたくない場合に重要です。 LALR(またはLR)の制限を満たします。
一種の有名な例として、C ++はLALR構文解析をしている人たちにとって、構文解析が非常に難しいと考えられています。C ++は、C ++リファレンスマニュアルの裏に記載されているほとんどの規則を使用して、GLR機構を使用して簡単に解析できます。(私はまさにそのようなパーサーを持っており、それはバニラC ++だけでなく、さまざまなベンダーの方言も扱います。これは、GLRパーサー、IMHOを使用しているため、実際にのみ可能です)。
[2011年11月編集:すべてのC ++ 11を処理できるようにパーサーを拡張しました。GLRはそれをはるかに簡単にしました。2014年8月の編集:C ++ 17のすべてを処理するようになりました。何も壊れたり悪化したりすることはなく、GLRはまだ猫の鳴き声です。]