2

Javaコードレベルからパーサーとレキサーに直接指示を与える方法はありますか? そうでない場合、どうすればこれを行うことができますか?

問題は、パーサーに変数を評価させ、バックアップしてから、その変数の値をオブジェクト名として割り当てたいということです。このような:

String s = "text";

SomeClass (s) = new SomeClass();

パーサーは読み取ります--> OK、s は「テキスト」と評価されます... パーサーはバックトラックしますが、「テキスト」をメモリに保持し、「テキスト」を SomeClass の新しいインスタンスの名前として割り当てます。これにより、次のことが可能になります。

text.callSomeMethod();

SomeClass の任意の数のオブジェクトをインスタンス化する必要があるため、これを行う必要があります。それぞれに一意の名前を付ける必要があり、次のようにするのが理想的です。

while (someArbitrarySet.hasNext()) {
    String s = "token" + Math.random();
    SomeClass (s) = new SomeClass();
    (s).callSomeMethod();
}

これが理にかなっていることを願っています...

4

5 に答える 5

1

What you're asking for is what some languages call MACROS. They're also sometimes known as preprocessor definitions, or simply "defines".

A decision was made to not have includes and macros and the like in Java because it introduces additional code maintenance concerns that the designers concluded was going to cause code that would not have been in the style they wanted.

However, just because it's not built into the compiler doesn't mean you couldn't add it to your build script.

As part of your build, you copy all files to a src-comp directory, and as you do, replace your tokens as they're defined.

I don't recommend doing it, but that doesn't mean it isn't possible.

于 2011-02-23T00:41:46.543 に答える
1

あなたが説明すること (実行時に新しい名前付き変数を作成すること) は、JavaScript、Lua、Bash などのインタープリター言語では可能ですが、Java などのコンパイル済み言語では可能ではありません。ループが実行されるとき、操作するソース コードはなく、すべての名前付き変数は事前に定義する必要があります。

これとは別に、変数に「一意の」名前は必要ありません。変数を順番に (次々に) 使用している場合は、ループを次のように書くこともできます。

while (someArbitrarySet.hasNext()) {
    SomeClass sC = new SomeClass();
    sC.callSomeMethod();
}

同時にオブジェクトが本当に必要な場合は、それらをある種のデータ構造に入れます。最も単純なのは配列です。キーでそれらを再度見つけたい場合は、Collection (ArrayList など) または Map (CajunLuke が書いたような) を使用できます。

実際、配列 (Java の場合) は変数 (すべて同じ型) のコレクションに他ならず、int によってインデックスを付けることができます。

(そして、実行時に新しい変数を作成できるスクリプト言語は、ある種のマップ String → (anything) でこれを実装します。このマップは、メソッド/スクリプトローカルまたは周囲のオブジェクトに属します。)


質問へのコメントに書きました(これらのことを質問自体に追加することをお勧めします。「編集」ボタンがあります):

あまり詳細には触れませんが、私はより大きなプログラム内で実行されるアプリケーションを作成しています。通常、オブジェクトは処理が終わった後にガベージ コレクションされますが、より大きなプログラムがオブジェクトを維持するため、それぞれに一意の名前が必要です。それぞれに一意の名前を付けないと、古いオブジェクトが上書きされますが、より大きなプログラムのコンテキストでは依然として必要です。

では、ガベージ コレクションを回避するためにオブジェクトを保持したいですか? 配列 (またはリストなど) を使用します。

問題は、大規模なプログラムでこれらのオブジェクトを使用できるようにしたい場合は、何らかの形でこの大規模なプログラムにオブジェクトを渡す必要があるということです。そして、このプログラムはこれらのオブジェクトへの参照を保持する必要があるため、ガベージ コレクションを回避できます。つまり、存在しない手段で存在しない問題を解決したいようです:-)

于 2011-02-23T00:47:59.840 に答える
0

あなたが尋ねた質問に対する実際の答えではありませんが、あなたの問題に対する解決策として考えられるのは、地図を使用することです。

Map variables = new HashMap();
while (someArbitrarySet.hasNext()) {
    String s = "token" + Math.random();
    variables.put(s, new SomeClass());
    variables.get(s).callSomeMethod();
}

そうすれば、「変数名」をマップへのキーとして使用でき、レクサー/パーサーをいじることなくやり遂げることができます。

Javaであなたが述べたことを具体的に行う方法があることを本当に願っています-それは本当にクールでしょう.

于 2011-02-23T00:38:11.477 に答える
0

いいえ、それはできません。

できたとしても、それらを正常に参照できるコンパイルコードがないため、それらを呼び出す方法を考えることはできません。

したがって、オプションはCanjuLukeによって説明されているものか、おそらくANTRLサンプルJava文法を使用して独自のJavaパーサーを作成し、そこに必要なものをフックすることです。

マップ ソリューションを考えてみましょう。

于 2011-02-23T00:47:54.593 に答える
0

これは、How do you use Java 1.6 Annotation Processing to perform compile time weaving?で回答されています。.

つまり、Java 構文を拡張し、Java 注釈にコンパイルする DSL を作成できる注釈処理ツールがあります。

JDK 1.5aptでは、代わりにを使用する必要がありましjavacたが、1.6 では、これらは-processorto フラグの影響を受けjavacます。からjavac -help:

-processor <class1>[<class2>,<class3>...]Names of the annotation processors to run; bypasses default discovery process
-processorpath <path>      Specify where to find annotation processors
于 2011-02-23T01:05:21.960 に答える