0

私は9つの異なる文法を持っています. 解析しているファイルの txt の最初の行に応じて、これらのいずれかが読み込まれます。

レクサー/パーサーのスポーンを 9 月に派生させることを考えていました。クラスを作成してから、一致するものを取得したらすぐにそれらをインスタンス化します。ただし、それによって速度が低下するかどうかはわかりません。私はいくつかのベンチマークが整っていると思います。

本当に、速度は間違いなくここでの私の目標ですが、これが醜いコードであることはわかっています。

現在、コードは次のようになっています。

sin.mark(0)
site = findsite(txt)
sin.reset()

if ( site == "site1") {
   loadlexer1;
   loadparser1;
} else if (site == "site2") {
   loadlexer2;
   loadparser2;
}
.................
} else if (site == "site8") {
   loadparser8;
   loadparser8;
}

findsite(txt) {
  ...................
  if line.indexOf("site1-identifier") {
    site = site1;
  } else if(line.indexOf("site2-identifier") {
    site = site2;
  } else if(line.indexOf("site3-identifier") {
    site = site3;
  }
  .........................
  } else if(line.indexOf("site8-identifier") {
    site = site8;
  }
}

いくつかの説明

1) はい、私は antlr で構築した 9 つの異なる文法を本当に持っているので、それらはすべて独自のレクサー/パーサー obj を持ちます。

2) はい、現時点では文字列を比較しており、明らかに何らかの整数マップに置き換えられます。サイト識別子を 1 つの正規表現にまとめることも検討しましたが、それによって速度が向上するとは思えません。

3) はい、これは疑似コードなので、ここでのセマンティクスにあまりこだわりません..

4) lexer/parser ペアの 1 つのインスタンスを作成できないという点で、kdgregory は正しいです。

コードの見栄えを良くするためのハッシュのアイデアは気に入っていますが、速度が上がるとは思いません。

4

11 に答える 11

7

標準的なアプローチは、マップを使用して、キー文字列をそれらを処理するレクサーに接続することです。

Map<String,Lexer> lexerMap = new HashMap<String,Lexer>();
lexerMap.put("source1", new Lexer01());
lexerMap.put("source2", new Lexer02());
// and so on

使用するレクサーを識別する文字列を取得したら、次のようにマップから取得します。

String grammarId = // read it from a file, whatever
Lexer myLexer = lexerMap.get(grammarId);

ただし、サンプルコードにはいくつかの癖があります。まず、indexOf()呼び出しは、スタンドアロンの文字列がないことを示し、Mapは文字列の内部を調べません。したがって、読み取った文字列から実際のキーを抽出する方法が必要です。

次に、レクサーとパーサーは通常状態を維持するため、単一のインスタンスを作成して再利用することはできません。これは、ファクトリクラスを作成し、それをマップに格納する必要があることを示しています(これはAbstract Factoryパターンです)。

さまざまなレクサー/パーサーが多数あると予想される場合は、マップ駆動型のアプローチを使用するのが理にかなっています。少数の場合、if-elseチェーンがおそらく最善の策であり、適切にカプセル化されています(これはファクトリメソッドパターンです)。

于 2009-05-21T16:51:57.850 に答える
2

ポリモーフィズムを使用すると、文字列操作よりも高速であることがほぼ保証され、コンパイル時に正確性がチェックされます。本当にsite文字列ですか?その場合、FindSite を GetSiteName と呼ぶ必要があります。FindSite がSite適切なレクサーとパーサーを知っているオブジェクトを返すことを期待します。

もう 1 つの速度の問題は、コーディングの速度です。個々のクラスに異なるレクサーとパーサーを配置する方が確実に優れています (おそらく別のクラスで共有機能を使用)。これにより、コードがわずかに小さくなり、誰かが理解しやすくなります。

于 2009-05-21T16:42:03.177 に答える
1

条件付きをポリモーフィズムに置き換える

中途半端な場合、findsite()の場合は、HashMapを設定するだけで、サイトIDからサイトに移動できます。別のクリーンアップは、単にサイト文字列を返すことです。したがって、次のようになります。

String findsite(txt) {
  ...................
  if line.indexOf("site1-identifier") 
    return site1;
  if(line.indexOf("site2-identifier")
    return  site2;
  if(line.indexOf("site3-identifier")
    return  site3;
...
}

このようにindexOf()を使用することは、実際には表現力がありません。equals()またはcontains()を使用します。

于 2009-05-21T16:55:37.407 に答える
1

レクサー/パーサーのスポーンをsepに派生させることを考えていました。クラスを作成し、一致するとすぐにインスタンス化します

すでに答えがあるようです。これにより、より柔軟なコードが作成されますが、それほど速くは必要ありません。

いくつかのベンチマークが適切だと思います

はい、両方のアプローチで測定し、十分な情報に基づいて決定を下します。私の推測では、あなたがすでに持っている方法で十分でしょう。

おそらく、「キロメートル」メソッドを使用するのが面倒な場合は、 extractメソッドを使用してさまざまな関数でリファクタリングすることができます。

最も重要なことは、最初に、低速でも機能するソリューションを用意し、それを機能させたら、プロファイルを作成して、パフォーマンスを向上させることができるポイントを検出することです。「最適化のルール」を覚えておいてください

于 2009-05-21T17:01:48.270 に答える
1

コードが非効率的だとします。

実際に入力を解析するのに(たとえば)1%以上の時間がかかりますか?

そうでなければ、あなたはより大きな「揚げる魚」を持っています。

于 2009-05-21T17:05:25.330 に答える
1

何かのようなもの:

Map<String,LexerParserTuple> lptmap = new HashMap<String,LexerParserTuple>();
lpt=lptmap.get(サイト)
lpt.loadlexer()
lpt.loadparser()

string.indexOf() ではなく正規表現マジックと組み合わせてサイトの名前を取得すると、コードが大幅にクリーンアップされます。

于 2009-05-21T16:51:20.693 に答える
0

マップを使用して、サイトをロード戦略構造に構成します。次に、「サイト」に基づいて単純なルックアップが必要になり、適切な戦略を実行します。findSite()についても同じことができます。

于 2009-05-21T16:55:27.050 に答える
0

識別子とサイトのマップを作成してから、マップエントリを反復処理することができます。

// define this as a static somewhere ... build from a properties file
Map<String,String> m = new HashMap<String,String>(){{
    put("site1-identifier","site2");
    put("site2-identifier","site2");
}}

// in your method
for(Map.Entry<String,String> entry : m.entries()){
    if( line.contains(entry.getKey())){
        return line.getValue();
    }
}

クリーナー:はい速い:わからない...十分に速いはず

于 2009-05-21T16:55:41.353 に答える
0

あなたはおそらく反射を使うことができます

char site = line.charAt(4);
Method lexerMethod = this.getClass().getMethod( "loadLexer" + site, *parameters types here*)
Method parserMethod = this.getClass().getMethod( "loadparser" + site, *parameters types here*)

lexerMethod.invoke(this, *parameters here*);
parserMethod.invoke(this, *parameters here*);
于 2009-05-21T16:55:56.550 に答える
0

findsiteのタイプを変更して、サイトタイプ(スーパークラス)を返し、ポリモーフィズムを活用します...これは文字列操作よりも高速である必要があります...

個別のレクサーが必要ですか?

于 2009-05-21T16:52:47.257 に答える
0

Javaについてはわかりませんが、一部の言語ではスイッチが文字列を取ることができます。

switch(site)
{
    case "site1": loadlexer1; loadparser1; break;
    case "site2": loadlexer2; loadparser2; break;
    ...
}

秒ビットについては、正規表現を使用して識別子を抽出し、それをオンにします。を使用したほうがよい場合がありますenum

于 2009-05-21T20:11:16.203 に答える