パーサーのコンビネーターを使い始めたときの最初の反応は、構文解析と字句解析の間の人為的な区別のように感じられたものからの解放感でした。突然、すべてがただ解析されていました!
しかし、私は最近遭遇しました this 誰かがこの区別を復活させることを示すcodereview.stackexchangeへの投稿。最初はこれは非常にばかげていると思いましたが、Parsecにはこの振る舞いをサポートする関数が存在するという事実から、自分自身に疑問を投げかけます。
パーサーコンビネーターで既に字句解析されたストリームを解析する場合の長所と短所は何ですか?
解析の下では、文脈自由言語の分析が最もよく理解されています。文脈自由言語は通常の言語よりも強力であるため、パーサーは(ほとんどの場合)字句解析器の作業をすぐに実行できます。
しかし、これはa)かなり不自然ですb)しばしば非効率的です。
A)について、たとえばif
式がどのように見えるかについて考える場合、IF expr THEN expr ELSE expr 「i」「f」ではなく、いくつかのスペース、そして式が始まる任意の文字など、あなたはアイデアを得ます。
B)には、識別子、リテラル、あらゆる種類の角括弧など、字句エンティティを認識する優れた仕事をする強力なツールがあります。これらのツールは、実質的にすぐに作業を行い、Niceインターフェイス(トークンのリスト)を提供します。パーサーのスペースをスキップする心配はもうありません。パーサーがトークンではなく文字を扱う場合、パーサーはより抽象的になります。
結局のところ、パーサーが低レベルのもので忙しいはずだと思うなら、なぜ文字を処理するのでしょうか?ビットのレベルでもそれを書くことができます!ご覧のとおり、ビットレベルで機能するこのようなパーサーはほとんど理解できません。文字やトークンも同様です。
ちょうど私の2セント。
字句解析器は通常の言語を認識し、パーサーは文脈自由言語を認識します。それぞれの通常の言語もコンテキストフリーであるため(いわゆるright-linear grammarで定義できます)、パーサーは通常の言語も認識でき、パーサーと字句アナライザーの違いは次のようになります。不要な複雑さ:単一の文脈自由文法(パーサー)は、パーサーと字句解析器の役割を果たします。
一方、文脈自由言語のいくつかの要素を通常の言語(したがって、字句解析器)を介してキャプチャすると便利な場合があります。
したがって、構文解析と字句解析を分離することには、より単純な文脈自由文法を使用し、いくつかの基本的な(通常はルーチンの)タスクを字句解析器(divide et impera)にカプセル化できるという利点があります。
[〜#〜]編集[〜#〜]
私はパーサーのコンビネーターに精通していないので、上記の考慮事項がそのコンテキストでどのように適用されるのかわかりません。私の印象は、パーサのコンビネータを使用しても、文脈自由文法が1つしかない場合でも、2つのレベル(字句解析/構文解析)を区別することで、この文法をよりモジュール化できるようになるということです。前述のように、下位の字句解析レイヤーには、識別子、リテラルなどの基本的な再利用可能なパーサーを含めることができます。
単純に、字句解析と構文解析は、複雑さが異なるため、分離する必要があります。字句解析はDFA(確定的有限オートマトン)であり、パーサーはPDA(プッシュダウンオートマトン)です。これは、構文解析が本質的に字句解析よりも多くのリソースを消費することを意味します。 DFAのみ。さらに、有限状態マシンの記述はそれほど複雑ではなく、自動化が簡単です。
Lexに構文解析アルゴリズムを使用するのは無駄です。
個別の解析/ Lexの主な利点の1つは、中間表現-トークンストリームです。これは、他の方法ではLex /解析の組み合わせでは不可能なさまざまな方法で処理できます。
とは言っても、パーサージェネレーターを学習するよりも、再帰的なまともな方法の方が複雑で作業しやすく、パーサージェネレーターのルール内で文法の弱点を表現する方法を理解する必要があることがわかりました。