今日のパーサジェネレータツール での相対的な人気を保証するために、LLパーサはLRパーサよりもどのような利点がありますか?
Wikipedia によると、LR構文解析はLLよりも優れているようです。
LR解析は、LL解析よりも広範囲の言語を処理でき、エラーレポートにも優れています。つまり、入力が文法に準拠していない場合に構文エラーをできるだけ早く検出します。これは、バックトラッキングのためにエラー検出を文法の別のブランチに延期する可能性があるLL(k)(またはさらに悪いことにLL(*)パーサー)とは対照的であり、多くの場合、長い共通接頭辞を持つ論理和間でエラーをローカライズするのが難しくなります。
注:これは宿題ではありません。 AntlrがLLパーサジェネレーターであることに気付いたとき、私はただ驚いた(名前に「LR」が含まれているにもかかわらず!)。
GLRは、解析ツリー/フォレストが必要で、ブラックボックスを気にしない場合に最適です。 LR/LALRの競合を静的に解決するのではなく、徹底的なテストによって解析時にあいまいさをチェックするという犠牲を払って、必要なものを入力できます [〜#〜] cfg [〜#〜] 。これは良いトレードオフだと言う人もいます。このクラスの問題には、IraBaxterのDMSツールまたは無料のC++文法を備えたElkhoundが役立ちます。 [〜#〜] antlr [〜#〜] は、大規模なクラスの言語アプリケーションにも役立ちますが、トップダウンアプローチを使用して、セマンティック述語を許可するLL(*)と呼ばれる再帰下降パーサーを生成します。 。ここでは、述語を使用すると、CFGを超えて状況依存言語を解析できることを証明せずに述べます。プログラマーは、適切なエラー処理などのアクションを文法に挿入したり、シングルステップデバッグを好んだりします。 LLは3つすべてが得意です。 LLは私たちが手作業で行うことなので、理解しやすくなっています。 LRがエラーの処理に優れていることについてのウィキペディアのナンセンス を信じないでください。とは言うものの、ANTLRで多くのバックトラックを行う場合、LL(*)ではエラーが実際に悪化します(PEGにはこの問題があります)。
再バックトラック。 GLRは、PEG、ANTLR、およびその他の非決定論的戦略と同様に、推測(つまりバックトラック)も行います。非決定論的なLR状態では、GLRはサブパーサーを「フォーク」して実行可能なパスを試します。とにかく、LLにはエラー処理のための良いコンテキストがあります。 LRが式と一致していることを知っている場合、LLはそれが割り当て内の式またはIF
-条件付きであることを知っています。 LRはそれがどちらかにある可能性があることを知っていますが、確かではありません-そしてその不確実性がその力を得るところです。
GLRはO(n^3)
最悪の場合です。 Packrat/PEGはO(n)
最悪のケースです。 ANTLRは周期的な先読みDFAのためにO(n^2)
ですが、実際にはO(n)
です。本当に関係ありません。 GLRは十分に高速です。
[〜#〜] antlr [〜#〜]は[〜#〜] an [〜#〜] other[〜#〜] t [〜#〜]ool for [〜#〜] l [〜#〜]ang[〜#〜] r [〜#〜]エコグニションはアンチLRではありませんが、私もそれが好きです;)
率直に言って、80年代の多くの若いコーダーのように、私はLALRを理解せず、ブラックボックスも好きではありませんでした(今はGLRエンジンの美しさを掘り下げましたが、それでもLLを好みます)。私は商用のLL(k)ベースのコンパイラを構築し、手作業で構築したものを生成するツールを構築することにしました。 ANTLRは万人向けではなく、C++のようなエッジケースはGLRでより適切に処理される可能性がありますが、多くの人々はANTLRが自分の快適ゾーンに適合すると感じています。 2008年1月以降、ANTLRWorks内でANTLRのバイナリjarが134,000回ダウンロードされ、ソースzipが合計されています(Google Analyticsによる)。たくさんの経験的データがあるLL(*)の 私たちの論文 を参照してください。
1つを手作業でコーディングする必要がある場合、再帰下降(LL)は現実的に実行できるものです。 L(AL)Rパーサーを実際に手作業で作成することはできません。
最新のパーサジェネレーターがすべてのパーサー構造を処理し、スペースがそれほど問題にならないことを考えると、特定のパーサージェネレーターで有効にするために文法とそれほど戦う必要がないため、LRパーサーを好みます。 (「左再帰をすべて削除する」愚かさはありません)。
実際、私は GLRパーサー を好みます。これは、文脈自由文法でほとんどすべてを解析します。左再帰の心配はありません。シフト/紛争の心配を減らすことはありません。先読みの制限はありません。
oneGLR解析エンジンが処理できる言語の範囲を確認したい場合(有名な解析が難しいLL/LALR言語を含む) 、C++)、あなたは見ることができます ここ 。
私の個人的な経験(私はさまざまな状況で両方を使用しました)から、最も実用的な違いは、LL(k)を使用すると、多くの可能な削減を気にせずに、より簡単な方法で文法を定義できることです(トップダウンであるため)。 LRパーサーで頻繁に発生する競合を削減またはシフト削減します。あなたが気にしなければならない唯一のことは、右再帰に変換されなければならない左再帰です。
もう1つのことは、トップダウンアプローチは、解析中にツリー全体を格納する必要があり、あいまいさが解決されるまで大きくなる可能性があるため、通常、(スペースまたは時間のいずれかに関して)より複雑になることを意味します。
私が今までよく知っている唯一の利点は、LLパーサーを手動で簡単にコーディングできることです。 LRパーサは、手動でコーディングするのが非常に困難です(通常はパーサジェネレータを使用します)。
LL解析のワーストケースの複雑さはO(n ^ 4)ですが、LR解析のワーストケースの複雑さはO(n ^ 3)の方が優れています。
(しかし、誰もO(n ^ 4)文法を書くことはありません。)