バッファリングされていないストリームを正しく使用していると思います。表示されるのは、これらのストリームを使用した場合に期待される望ましい結果です。しかし、あなたは彼らが会う義務がないという彼らの期待を持っているかもしれないと思います。
以下は、スティックで突くためのテストコードです。入力に使用System.in
しているので、単語トークン間の改行文字を考慮して文法を変更しました。
Streaming.g
grammar Streaming;
fox : 'quick' NL 'brown' NL 'fox' NL DONE NL;
DONE : 'done';
NL : '\r'? '\n';
StreamingTest.java
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.CommonTokenFactory;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.UnbufferedCharStream;
import org.antlr.v4.runtime.UnbufferedTokenStream;
import org.antlr.v4.runtime.tree.TerminalNode;
public class StreamingTest {
public static void main(String[] args) throws Exception {
lex();
parse();
}
private static void lex() {
System.out.println("-> Reading from lexer:");
UnbufferedCharStream input = new UnbufferedCharStream(System.in);
StreamingLexer lexer = new StreamingLexer(input);
lexer.setTokenFactory(new CommonTokenFactory(true));
Token t;
//read each token until hitting input "done"
while ((t = lexer.nextToken()).getType() != StreamingLexer.DONE){
if (t.getText().trim().length() == 0){
System.out.println("-> " + StreamingLexer.tokenNames[t.getType()]);
} else {
System.out.println("-> " + t.getText());
}
}
}
private static void parse() {
System.out.println("-> Reading from parser:");
UnbufferedCharStream input = new UnbufferedCharStream(System.in);
StreamingLexer lexer = new StreamingLexer(input);
lexer.setTokenFactory(new CommonTokenFactory(true));
StreamingParser parser = new StreamingParser(new UnbufferedTokenStream<CommonToken>(lexer));
parser.addParseListener(new StreamingBaseListener(){
@Override
public void visitTerminal(TerminalNode t) {
if (t.getText().trim().length() == 0){
System.out.println("-> " + StreamingLexer.tokenNames[t.getSymbol().getType()]);
} else {
System.out.println("-> " + t.getText());
}
}
});
parser.fox();
}
}
以下は、上記のプログラムのレクサーとパーサーに提供/受信される入力と出力の組み合わせです。出力の各行の前には。が付いてい->
ます。その後、どうしてそうなるのかを説明します。
入出力
-> Reading from lexer:
quick
-> quick
brown
-> NL
-> brown
fox
-> NL
-> fox
done
-> NL
-> Reading from parser:
quick
brown
-> quick
-> NL
fox
-> brown
-> NL
done
-> fox
-> NL
-> done
-> NL
私が最初に気付くのは、レクサーquick
NL
が入力をすぐに受け取ったが、のトークンしか提供しなかったことですquick
。この不一致の理由は、空の先読み文字バッファーに配置されないためUnbufferedCharStream
、(完全に優れたトークンが用意されていても)もう1文字先読みするためです。NL
残念ながら、バッファリングされていないストリームはバッファリングされます。クラス自体のJavadocコメントによると:
ここでの「バッファなし」とは、すべてのデータをバッファリングするわけではなく、charのオンデマンドロードではないという事実を指します。
この余分な読み取りは、ストリームでさらに入力を待機することを意味します。これは、レクサーが残りの入力に対して1トークン遅れている理由を説明しています。
次に、パーサーに移ります。なぜそれはレクサーのものに2つのトークンより遅れているのですか?単純:UnbufferedTokenStream
空の先読みバッファーにも配置されないため。ただし、次のトークンは、a)レクサーからのスペアトークンがあり、b)レクサーUnbufferedCharStream
が独自の先読み文字を読み取るまで作成できません。事実上、これはレクサーの1文字の「ラグ」と1トークンの「ラグ」です。
ANTLR v4で「ラグのない」データオンデマンドストリームを取得することは、独自のストリームを作成することを意味するようです。しかし、既存のストリームは期待どおりに機能しているように見えます。
Antlrは、解析するテキストの直後にEOFがないストリームからのデータを解析するのに適していますか?
ANTLR4についてはまだ自信を持って答えることはできません。必要になるまで先にバッファリングしないトークンストリームを作成するのは簡単なようですが(呼び出しをスキップするためにUnbufferedTokenStream
オーバーライドします)、文字ストリームは、他の人のバッファリングに関係なく、独自の読み取りを行うクラスによって呼び出されます。またはそう思われます。私はできる限りこれを掘り下げていきますが、これを行うための公式の方法を学ぶ必要があるかもしれません。consume
sync