最も重要な違いは、字句解析によって入力ドメインが変換されることです。
これの良い結果はそれです
ただし、字句解析を実行すると、次のような問題が発生します。
で一般的なパーサーを使用することはできなくなりましString
た。たとえば、ライブラリ関数(文字列入力ストリームで動作する)を使用して数値を解析する場合は、解析結果を検査するために、パーサーのような操作を行う必要があります(通常はparseFloat :: Parsec String s Float
)。これは書くのが面倒で、構成可能性を制限します。takeNextToken :: TokenParser String
execute
parseFloat
Either ErrorMessage a
すべてのエラーメッセージを調整しました。トークンのパーサーが20番目のトークンで失敗した場合、入力文字列のどこにありますか?エラーの場所を手動で入力文字列にマップする必要がありますが、これは面倒です(Parsecでは、これはすべてのSourcePos
値を調整することを意味します)。
エラー報告は一般的に悪いです。string "hello" *> space *> float
のような間違った入力で実行すると、"hello4"
の後に空白が欠落していることが予想されますがhello
、レクサーは。を見つけたと主張します"invalid token"
。
アトミックユニットであり、レクサーによって分離されると予想される多くのことは、実際には、レクサーが識別するにはかなり「難しすぎる」ものです。たとえば、文字列リテラルは、突然"hello world"
2つのトークン"hello
ではなくなりworld"
ます(ただし、もちろん、引用符がエスケープされていない場合のみ\"
)。これはパーサーにとっては非常に自然なことですが、レクサーにとっては複雑なルールと特殊なケースを意味します。
トークンでパーサーをうまく再利用することはできません。のdoubleを解析する方法を定義する場合はString
、それをエクスポートすると、世界中で使用できます。(特殊な)トークナイザーを最初に実行することはできません。
あなたはそれに固執しています。解析する言語を開発しているとき、レクサーを使用すると、早期の決定を下し、後で変更したいものを修正することにつながる可能性があります。たとえば、Float
トークンを含む言語を定義したとします。ある時点で、負のリテラル(-3.4
および- 3.4
)を導入する必要があります。これは、レクサーが空白をトークン区切り文字として解釈するために不可能な場合があります。パーサーのみのアプローチを使用すると、柔軟性を維持して、言語の変更を容易にすることができます。パーサーは本質的にルールをエンコードするより複雑なツールであるため、これはそれほど驚くべきことではありません。
要約すると、ほとんどの場合、レクサーフリーのパーサーを作成することをお勧めします。
結局のところ、レクサーは単なる「ダミングダウン」*パーサーです。とにかくパーサーが必要な場合は、それらを1つに結合します。
*コンピューティング理論から、すべての正規言語も文脈自由言語であることがわかります。レクサーは通常、通常のパーセクであり、コンテキストフリーまたはコンテキストセンシティブです(Parsecのようなモナディックパーサーはコンテキストセンシティブを表現できます)。