最初にDFAに変換する代わりにNFAを直接使用する実際のレクサーはありますか?


7

私はコンパイラでCourseraクラスを受講していますが、レクサーに関するレッスンでは、非決定性有限オートマトン(NFA)を使用して正規表現を解析する間に、決定論的有限オートマトン(DFA)との間に時空間トレードオフがあることを示唆しています。私が正しく理解している場合、トレードオフはNFAが小さいことですが、すべての可能な状態を同時に考慮する必要があるため、ほとんどの場合DFAに変換されるため、トラバースに時間がかかります。「実際の」生活でDFAの代わりにNFAを使用するレクサー、つまり、単なる概念実証ではなく、本番環境で使用されるコンパイラーはありますか?


「...すべての可能な状態を考慮する必要がある...」の代わりに、「...すべての可能な遷移を考慮する必要がある...」ということです。これは指数関数的に困難であり、状態の総数よりもすぐに大きくなる可能性があります。
Paresh 2013

私はこれについて肯定的ではありませんが、PROLOG自体が解析する方法はあなたの要件を満たしません。
ガイコーダー

回答:


4

最小化されたDFAの代わりにNFA(またはそれを書き留めずにそのパワーオートマトン)を使用する2つのアプリケーションのみが表示されます。

  1. ホモイコニック言語、レクサーを頻繁に変更する必要がある場合
  2. DFAを爆破するような奇妙な構文

    identifier := [a-z][a-z0-9_]*
    indices := [0-9_]{1,256} //up to 256 times
    var := identifier "_" indices | identifier
    

    最後のルールを優先する場合、レクサーは、最後の256シンボル内に識別子に「_」が含まれているかどうかを確認し、この場合は短くする必要があります。


1
サディストが私に第二言語を教えてくれたなら、私は厳格なFAの外でそれを扱います。たとえば、Cコンパイラは通常/*、コメントの開始を認識し、*/Cコードでのマッチングにスキップします。その上、それを含む言語は人間にとって読むのがほぼ不可能です。
フォンブランド2013年

これは自然な例ではありませんでしたが、Cでも、過度に悪用されずに、構文の過度の悪用が可能であったとしても、それほど読みにくいものではありません。これをC(モードスイッチ)でコメントのように処理することは、可能な識別子の終わりに依存するため、それほど簡単ではありません。(「サディスト」の+1)。
frafl 2013年

4

コンパイルされた字句解析器は、NFAをDFAにコンパイルします。

グッドは解釈メモ化でNFAをシミュレートし、一方で、トンプソンのアルゴリズムを使用して、正規表現マッチャーを。これは、NFAをDFAにコンパイルするのと同じですが、DFA状態が必要な場合にのみ、オンデマンドで生成します。各ステップでの確定的状態は一連のNFA状態であり、次の入力文字を指定すると、新しい一連のNFA状態に移行します。以前に確認した状態とその出力遷移をハッシュテーブルにキャッシュします。ハッシュテーブルは、いっぱいになるとフラッシュされ、無限に大きくなることはありません。

この方法で行う理由は、NFAをDFAに変換すると、正規表現のサイズが指数関数的に増加する可能性があるためです。正規表現を1回だけ評価する場合、これは確かにしたいことではありません。

RE2は、Thompsonのアルゴリズムを(本質的に)使用する正規表現エンジンの例です。詳細を知りたい場合は、RE2の作者であるRuss Coxによる素晴らしいブログ投稿をお勧めします(多くの履歴情報や正規表現検索へのさまざまなアプローチの実験的比較など)。

また、「GNU grepが高速である理由」メールチェーンを強くお勧めします。レッスン1は次のとおりです。正規表現検索の一般的なケースは単純な文字列検索なので、特別なケースはアルゴリズムです。


3

彼らがそうした場合、私は驚かれることでしょう。レクサーの構築は1回(うまくいけば)実行され、結果数百万回使用されます(中規模のソースファイルにトークンがいくつあるかを考えてください)。したがって、非常に異常な状況でない限り、レクサーをできるだけ高速に(そして他のリソースを質素に)すること、つまり最小限のDFAを採用することは報われます。


1
最小のDFAは、指数関数的にサイズが大きくなる可能性があります。大きすぎる場合は、DFAを保存するよりもNFAを探索する方が合理的です。とはいえ、どのシステムでもそれが考慮されていることはわかりません。
ラファエル

0

厳密な正式な意味では、違います。理論/数学的な意味での非決定性により、マシンは、入力の先を見ることなく、最終的に受け入れ状態になるかどうかに基づいて計算パスを選択できます。したがって、この厳密な意味では、これは理論的な検討にのみ適しているプロパティであり、実際の非決定的マシンなどはありません。この場合、特に、将来を見通すことができない限り、実際にNFAを構築することはできません。この才能を備えたコンパイラを構築するのは少し無駄です!;)。

ただし、非決定性と非決定性は、漠然と定義された弱い意味で使用されることがよくあります。時々それはランダム化/確率論を意味するかもしれません-アルゴリズムはコインを裏返す、正式な設定ではこれは確率論的/ランダム化アルゴリズムとして研究され、非決定論とは呼ばれません。別の用途は、同じ入力で2回実行した場合に同じ出力を必ずしも生成しないアルゴリズムです。ランダムではないかもしれませんが、動作の一部が指定されていないため、いくつかの有効な出力がある可能性があります(個人的には定義は混乱から来て来ていないが -determinedと -deterministic。

それでも、原則として、これらの弱い非公式な感覚の1つで非決定的であるレクサーを作成できますが、それはNFA(厳密な正式なマシンモデル)ではなく、クラッシュになるとは想像できません。ホットアイデアのいずれか-レクサーは非常に予測可能である必要があります。

最後のオプションは、バックトラッキングまたは並列処理を介して非決定論をシミュレートできることですが、この場合、非決定論の見かけの効率が失われます。 DFAよりもオフ。


この特定のケースでは、NFAが適度なスペースコストであり得るすべての可能な状態を追跡することは非常に可能であり、本質的には、計算ツリーの幅の最初のスイープを並列で実行します。水晶玉は必要ありません。
フォンブランド2013年

@vonbrandは、NFAからDFAへの変換のパワーセットの賢明なバージョンが実行するものなので、DFAに戻ります。
ルークマシソン2013年

OPは実装に関する質問です。このコンテキストでは、DFAとNFAの違いは、DFAではすべての状態がすべての可能な入力シンボルに対して1つの出力遷移を持つことです。この文脈でのNFAは、各状態が入力シンボルごとに0、1、または多くの出力遷移を持つことができる状態マシンであり、また、ϵ遷移。OPは、実際には(決定論的に)NFAを(状態のセットを維持することによって)シミュレートするのか、それともNFAをDFAにコンパイルしてからDFAを実行するのかを尋ねています。「実際の」非決定性があるかどうかは関係ありません。
Wandering Logic
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.