レクサーとパーサーの理論は本当に違いますか?
正規表現を嫌うのは流行のようです: coding horror 、 another blog post 。
ただし、人気のある字句解析ベースのツール: pygments 、 geshi 、または prettify 、すべて正規表現を使用します。彼らは何でもレックスに見える...
いつ字句解析が十分で、いつEBNFが必要ですか?
誰かがこれらのレクサーによって生成されたトークンをbisonまたはantlrパーサージェネレーターで使用しましたか?
パーサーとレクサーの共通点:
*
、==
、<=
、^
は、C/C++ lexerによって「演算子」トークンとして分類されます。[number][operator][number]
、[id][operator][id]
、[id][operator][number][operator][number]
は、C/C++パーサーによって「式」非終端記号として分類されます。[TXT][TAG][TAG][TXT][TAG][TXT]...
に変換します。ご覧のとおり、パーサーとトークナイザーには多くの共通点があります。 1つのパーサーは他のパーサーのトークナイザーになることができます。これは、ある言語の文が他の高レベルのアルファベット記号になるのと同じ方法で、入力トークンを独自のアルファベット(トークンは単にアルファベットの記号)からのシンボルとして読み取ります言語。たとえば、*
と-
がアルファベットのシンボルM
(「モールス符号シンボル」として)である場合、これらのドットと行の文字列をモールス符号でエンコードされた文字として認識するパーサーを構築できます。言語「モールスコード」の文は、他のパーサーではtokensである可能性があり、これらのtokensはその言語のアトミックシンボルです(例:「英語の単語」言語)。そして、これらの「英語の単語」は、「英語の文章」言語を理解するより高いレベルのパーサーのトークン(アルファベットの記号)である可能性があります。 これらの言語はすべて、文法の複雑さのみが異なります。これ以上何もない。
では、これらの「Chomskyの文法レベル」とは何ですか?ノーム・チョムスキーは、文法をその複雑さに応じて4つのレベルに分類しました。
a
、b
)の記号、連結(ab
、aba
のみで構成できます。 、bbb
etd。)、または代替(例a|b
)。(()()(()()))
、ネストされたHTML/BBcodeタグ、ネストされたブロックなど。それを処理する状態オートマトンは、無限に多くのネストレベルを処理するために無限に多くの状態を持たなければならないからです。x+3
があり、あるコンテキストではこのx
が変数の名前になり、別のコンテキストでは関数の名前になります。はい、それらは理論と実装が大きく異なります。
レクサーは、言語要素を構成する「単語」を認識するために使用されます。これは、そのような単語の構造が一般に単純だからです。正規表現は、この単純な構造の処理に非常に優れており、レクサーの実装に使用される非常に高性能な正規表現照合エンジンがあります。
パーサーは、言語フレーズの「構造」を認識するために使用されます。通常、このような構造は「正規表現」が認識できる範囲をはるかに超えているため、そのような構造を抽出するには「コンテキスト依存」パーサーが必要です。コンテキスト依存パーサーは構築が難しいため、エンジニアリング上の妥協点は、「コンテキストフリー」文法を使用し、パーサーにハック(「シンボルテーブル」など)を追加して、コンテキスト依存部分を処理することです。
字句解析技術も構文解析技術もすぐになくなることはないでしょう。
いわゆるスキャナーレスGLRパーサーで現在調査されているように、「解析」テクノロジーを使用して「単語」を認識することを決定することで、これらのが統合される場合があります。多くの場合、それを必要としない問題で、通常はオーバーヘッドで支払います。多くの空きサイクルがある場合、そのオーバーヘッドは重要ではありません。大量のテキストを処理する場合、オーバーヘッドは重要であり、古典的な正規表現パーサーは引き続き使用されます。
質問に答える(他の回答に表示される内容を過度に繰り返すことなく)
レクサーとパーサーは、受け入れられた答えが示唆するように、それほど違いはありません。どちらも単純な言語形式に基づいています。レクサー用の通常言語と、ほとんどの場合、パーサー用のコンテキストフリー(CF)言語です。どちらも、かなり単純な計算モデル、有限状態オートマトン、プッシュダウンスタックオートマトンに関連付けられています。通常の言語はコンテキストフリー言語の特殊なケースであるため、レクサーはやや複雑なCF技術で作成できます。しかし、少なくとも2つの理由から、それは良い考えではありません。
プログラミングの基本的なポイントは、システムコンポーネントが最も適切なテクノロジを備えているため、作成、理解、および保守が容易であることです。技術は、必要以上に複雑でコストのかかる技術を使いすぎたり、力の限界に達してはならないため、目的の目標を達成するために技術的なゆがみが必要です。
それが「正規表現を嫌うのが流行のように見える」理由です。彼らは多くのことを行うことができますが、それを実現するために非常に読みにくいコーディングが必要になることがあります。実装のさまざまな拡張や制限が理論上の単純さをいくらか低下させるという事実は言うまでもありませんレクサーは通常それを行わず、通常、トークンを解析するためのシンプルで効率的で適切なテクノロジーです。トークンにCFパーサーを使用するのは過剰ですが、可能ですが。
字句解析にCF形式を使用しないもう1つの理由は、CFの全機能を使用したくなるかもしれないということです。しかし、それはプログラムの読み取りに関する構造的な問題を引き起こす可能性があります。
基本的に、プログラムテキストの構造のほとんどは、そこから意味が抽出され、ツリー構造です。構文規則から構文解析文(プログラム)が生成される方法を表します。意味論は、構文規則を構成して構文解析ツリーを構築する方法から、合成手法(数学指向の準同型)によって導き出されます。したがって、ツリー構造は不可欠です。トークンが通常のセットベースのレクサーで識別されるという事実は、レギュラーで構成されたCFがまだCFを与えるため、状況を変えません(私は、文字のストリームをトークンのストリームに変換する通常のトランスデューサーについて非常に大まかに言っています)。
ただし、CFで構成されたCF(CFトランスデューサーを介して...申し訳ありませんが)、必ずしもCFを与えるわけではなく、物事をより一般的にするかもしれませんが、実際には扱いにくくなります。そのため、CFは使用できますが、レクサーに適したツールではありません。
レギュラーとCFの大きな違いの1つは、レギュラー言語(およびトランスデューサー)がさまざまな方法でほぼすべての形式と非常によく構成されているのに対し、CF言語(およびトランスデューサー)はそうではなく、いくつかの例外を除きます)
(通常のトランスデューサには、構文エラー処理手法の形式化など、他の用途がある場合があることに注意してください。)
BNFは、CF文法を提示するための単なる特定の構文です。
EBNFはBNFの構文糖であり、通常の表記の機能を使用してBNF文法のより簡潔なバージョンを提供します。常に同等の純粋なBNFに変換できます。
ただし、通常の表記は、語彙要素の構造に対応する構文のこれらの部分を強調するためだけにEBNFでよく使用され、レクサーで認識される必要があり、残りはむしろストレートBNFで表示されます。しかし、それは絶対的な規則ではありません。
要約すると、トークンのより単純な構造は、通常の言語のより単純な技術でよりよく分析される一方、(プログラム構文の)言語のツリー指向構造は、CF文法によってより適切に処理されます。
AHRの答え も見ることをお勧めします。
しかし、これは質問を開いたままにします:なぜ木ですか?
ツリーは、構文を指定するための優れた基盤です。
テキストに単純な構造を与えます
上記のように、構造に基づいてセマンティクスをテキストに関連付け、数学的に十分に理解されている技術(準同型による合成)を使用してテキストを関連付けるのに非常に便利です。これは、数学的形式のセマンティクスを定義するための基本的な代数ツールです。
したがって、Abstract Syntax Trees(AST)の成功が示すように、これは優れた中間表現です。多くの専門家(LLやLRなど)が使用する解析技術はCF文法のサブセットにのみ適用されるため、ASTは解析ツリーとは異なることが多いため、ASTで修正される文法上の歪みを強制します。これは、CF文法を受け入れるより一般的な解析技術(動的プログラミングに基づく)で回避できます。
プログラミング言語はCFではなくコンテキスト依存(CS)であるという事実に関する声明は、arbitrary意的で議論の余地があります。
問題は、構文とセマンティクスの分離がarbitrary意的であることです。宣言または型の一致をチェックすることは、構文の一部またはセマンティクスの一部と見なされる場合があります。自然言語の性別と数の一致についても同じことが言えます。しかし、複数の一致が単語の実際の意味に依存する自然言語が存在するため、構文に適合しません。
表示的セマンティクスにおけるプログラミング言語の多くの定義は、セマンティクスに宣言と型チェックを配置します。したがって、 Ira Baxter によって行われるように述べることは、構文で必要とされるコンテキスト感度を得るためにCFパーサーがハッキングされているということは、せいぜい状況のarbitrary意的な見方です。一部のコンパイラではハックとして編成される場合がありますが、そうである必要はありません。
また、CSパーサー(ここの他の回答で使用されている意味で)を構築するのが難しく、効率が低いだけではありません。また、必要となる可能性のある状況依存性の種類をはっきりと表現するには不十分です。また、プログラムのセマンティクスを導出するのに便利な構文構造(解析ツリーなど)を自然に生成しません。つまり、コンパイルされたコードを生成します。
コンパイラの分析部分が通常、字句解析と解析(構文解析)フェーズに分けられる理由はいくつかあります。
resource ___Compilers(2nd Edition)written by- Alfred V. Abo Columbia University Monica S. Lam Stanford University Ravi Sethi Avaya Jeffrey D.Ullman Stanford University