6
なぜレクサーを2Dアレイと巨大なスイッチとして実装するのですか?
私は学位を取得するためにゆっくりと取り組んでおり、この学期はCompilers 101です。DragonBookを使用しています。まもなくコースに入り、語彙分析と、決定論的有限オートマトン(以下、DFA)を介してそれを実装する方法について説明します。さまざまなレクサーの状態を設定し、それらの間の遷移を定義します。 しかし、教授と本は両方とも、巨大な2D配列(1つの次元としてのさまざまな非終端状態、および他の可能性のある入力シンボル)に相当する遷移テーブルと、すべての端子を処理するswitchステートメントを介して実装することを提案していますまた、非終端状態の場合は遷移テーブルにディスパッチします。 理論はすべて良好で優れていますが、実際にコードを何十年も書いた人として、実装は下手です。それはテスト可能ではなく、保守可能でもなく、読み取り可能でもなく、デバッグするのに苦労します。さらに悪いことに、その言語がUTFに対応していれば、どのように実用的であるかわかりません。非終端状態ごとに100万程度の遷移テーブルエントリがあると、急いで扱いにくくなります。 それで、取引は何ですか?主題に関する決定的な本が、このようにそれをするように言っているのはなぜですか? 関数呼び出しのオーバーヘッドは本当にそれほどですか?これはうまく機能するものですか、文法が事前にわからない場合に必要ですか(正規表現)?または、より具体的なソリューションがより具体的な文法でうまく機能する場合でも、すべてのケースを処理する何かでしょうか? (注:可能性のある重複「なぜ巨大なswitchステートメントの代わりにオブジェクト指向アプローチを使用するのか?」は近いですが、オブジェクト指向については気にしません。機能的アプローチ、またはスタンドアロン関数での賢明な命令型アプローチでも問題ありません。) また、例のために、識別子のみを持つ言語を考えてみましょう[a-zA-Z]+。これらの識別子はです。DFA実装では、次のようなものが得られます。 private enum State { Error = -1, Start = 0, IdentifierInProgress = 1, IdentifierDone = 2 } private static State[][] transition = new State[][]{ ///* Start */ new State[]{ State.Error, State.Error (repeat until 'A'), State.IdentifierInProgress, ... ///* IdentifierInProgress */ new State[]{ State.IdentifierDone, …