1

私は次のようなパターンで構成される単純な言語を持っています

size(50*50)
start(10, 20, -x)
forward(15)
stop

これは亀を描く言語の例です。適切にトークン化する必要があります。上記はソースコードインスタンスです。ステートメントと式は改行で区切られます。改行などの区切り文字を使用するようにスキャナーを設定しました。next("start")「start」という文字列を食べることを期待してから、next("(")最初の括弧を食べる。しかし、それは私が期待する以外のことをしているように見えます。スキャナーはすでに上記を区切り文字に基づいてトークンに分割しましたか、および/またはこれに別の方法でアプローチする必要がありますか?私にとって、最初の行の「start」、「(」、「50」、「*」、「50」、「)」は別々のトークンを構成しますが、これはここでは満たされていない期待のようです。できるだけ少ないコードで上記をトークン化するにはどうすればよいですか?私は現在、トークナイザーを作成する必要はありません。インタープリターを作成しているので、トークン化は現在時間を費やしたくないものです。スキャナーがここで作業するのが好きです。

私のuseDelimiter電話は次のとおりです。

Scanner s ///...
s.useDelimiter(Pattern.compile("[\\s]&&[^\\r\\n]"));

最初の呼び出しを発行nextすると、ファイルの内容全体が表示されます。上記の呼び出しがなければ、それは私に最初の行全体を与えます。

4

2 に答える 2

3

適切なパーサーを作成するには、正式な文法で言語を定義する必要があります。私を信じてください、あなたはそれをきちんとやりたいです、さもなければあなたは下流で問題を抱えるでしょう。

おそらく、トークンを最下位レベルの正規表現として表すことができますが、最初に、語彙構造内のトークンの組み合わせである文法について明確にする必要があります。これは、プロダクションと呼ばれる再帰関数(メソッド)として表すことができます。各プロダクション関数は、スキャナーを使用して、必要なトークンを参照しているかどうかをテストできます。ただし、スキャナーは入力を消費するため、元に戻すことはできません。

Scannerを使用した場合、次のことが不適切であることがわかります。

  1. 常に正規表現に従ってトークンを解析します。

    1.1したがって、使用できるトークンを取得した場合でも、それがどのトークンであるかを正確に判断するには、さらにコードを記述する必要があります。

    1.2そしてあなたはあなたの言語文法を一つの大きな表現として表現することができないかもしれません

  2. 巻き戻すことはできません。先読みパーサー(あなたのような多くの文法に必要)は、入力ストリームを先読みし、必要に応じて、入力を使用せず、別のトークンパーサー関数に使用させるように決定できる必要があります。

文字レクサーを自分で作成し、ストリームではなく文字列/文字の配列を反復処理することをお勧めします。その後、巻き戻すことができます。

それ以外の場合は、 yaccCoco/Rなどの既成のレクサー/パーサーフレームワークを使用します。

于 2012-10-01T16:33:01.190 に答える
2

クラスjava.io.StreamTokenizerの方が適している場合があります。これは、再帰下降パーサーのこので使用されます。

補遺:クラスの主な違いは何 ですか?StreamTokenizer Scanner

どちらも、パーサーに必要な字句解析を実行できます。StreamTokenizer軽量ですが、事前定義された4つのメタトークンに制限されています。Scannerかなり柔軟性がありますが、使用するのがやや面倒です。これが2つの比較と後者のバリエーションです。

于 2012-10-01T16:38:19.057 に答える