Sockets 使用Antlr解析来自永无止境流的数据

Sockets 使用Antlr解析来自永无止境流的数据,sockets,stream,eof,antlr4,Sockets,Stream,Eof,Antlr4,Antlr是否适合解析来自在要解析的文本之后没有EOF的流的数据? 根据我的观察,lexer在收到下一个令牌的第一个字符之前不会发出当前令牌。 最重要的是,在收到下一个规则的第一个标记之前,解析器似乎不会发出该规则。 下面是我尝试过的一个简单语法: fox: 'quick' 'brown' 'fox' '\r'? '\n' ; 然后我将生成的解析器与UnbufferedCharStream和UnbufferedTokenStream一起使用: CharStream input = new

Antlr是否适合解析来自在要解析的文本之后没有EOF的流的数据? 根据我的观察,lexer在收到下一个令牌的第一个字符之前不会发出当前令牌。 最重要的是,在收到下一个规则的第一个标记之前,解析器似乎不会发出该规则。 下面是我尝试过的一个简单语法:

fox: 'quick' 'brown' 'fox' '\r'? '\n' ;
然后我将生成的解析器与UnbufferedCharStream和UnbufferedTokenStream一起使用:

  CharStream input = new UnbufferedCharStream(is);
  MyLexer lex = new MyLexer(input);
  lex.setTokenFactory(new CommonTokenFactory(true));
  TokenStream tokens = new UnbufferedTokenStream(lex);
  MyParser parser = new MyParser(tokens);
  MyParser.FoxContext fox = parser.fox();
当流变得“quick”时,什么也不会发生

当“b”进入时-输入规则“fox”

然后“roun”-什么都没有(流中有两个令牌-leser还不知道它们!)

只有在“f”之后,侦听器才会访问第一个标记:“quick”

然后-在“ox”上没有任何内容

在线(unix):访问令牌“brown”

现在,流具有所有数据(4个令牌),但只识别2个令牌

我发现,为了将这些令牌推送到系统中,流可以发出2个令牌,即语法已知的任何令牌。 它可能是两个额外的新品系,或者说“fox”和“brown”。 只有当令牌“fox”和“\n”被访问时,解析器才会退出规则“fox”并完成解析

这是一个bug还是一个特性? 有没有办法消除这种滞后


谢谢

我认为您正确地使用了无缓冲流,您看到的是使用这些流的预期结果。但我认为你可能对他们有期望,他们没有义务去满足

下面是我们用棍子戳的测试代码。我正在使用
System.in
进行输入,因此我修改了语法以考虑单词标记之间的换行符

流媒体.g
语法流;
狐狸:“快”NL“棕色”NL“狐狸”NL“完成”NL;
完成:“完成”;
NL:“\r”?”\n′;
StreamingTest.java
import org.antlr.v4.runtime.CommonToken;
导入org.antlr.v4.runtime.CommonTokenFactory;
导入org.antlr.v4.runtime.Token;
导入org.antlr.v4.runtime.UnbufferedCharStream;
导入org.antlr.v4.runtime.UnbufferedTokenStream;
导入org.antlr.v4.runtime.tree.TerminalNode;
公共类流化测试{
公共静态void main(字符串[]args)引发异常{
lex();
parse();
}
私有静态void lex(){
System.out.println(“->从lexer读取:”);
UnbufferedCharStream输入=新的UnbufferedCharStream(System.in);
StreamingLexer lexer=新的StreamingLexer(输入);
lexer.setTokenFactory(新的CommonTokenFactory(true));
令牌t;
//读取每个令牌,直到点击输入“完成”
而((t=lexer.nextToken()).getType()!=StreamingLexer.DONE){
if(t.getText().trim().length()==0){
System.out.println(“->”+StreamingLexer.tokenNames[t.getType()]);
}否则{
System.out.println(“->”+t.getText());
}
}
}
私有静态void parse(){
System.out.println(“->从解析器读取:”);
UnbufferedCharStream输入=新的UnbufferedCharStream(System.in);
StreamingLexer lexer=新的StreamingLexer(输入);
lexer.setTokenFactory(新的CommonTokenFactory(true));
StreamingParser=newstreamingparser(newunbufferedtokenstream(lexer));
addParseListener(新StreamingBaseListener(){
@凌驾
公共无效访问终端(终端节点t){
if(t.getText().trim().length()==0){
System.out.println(“->”+StreamingLexer.tokenNames[t.getSymbol().getType()]);
}否则{
System.out.println(“->”+t.getText());
}
}
});
parser.fox();
}
}
下面是输入和输出的混合,因为它们在上面的程序中提供给lexer和解析器,或者从中接收。每行输出都以
->
作为前缀。我会解释为什么事情会这样

输入与输出 我注意到的第一件事是lexer立即收到
quick
NL
进行输入,但只为
quick
提供了一个令牌。产生这种差异的原因是
UnbufferedCharStream
向前读取了一个字符(即使它有一个非常好的
NL
令牌为我准备好了!),因为它不会位于空的向前看字符缓冲区上。唉,未缓冲的流被缓冲了。根据类本身中的Javadoc注释:

这里的“Unbuffered”指的是它不会缓冲所有数据,而不是按需加载字符

这个额外的读取转换为等待流中更多的输入,这解释了为什么lexer在其余的输入中落后一个令牌

现在转到解析器。为什么它落后于lexer的一个标记的两个标记?简单:因为
无缓冲TokenStream
也不会位于空的前瞻缓冲区上。但它无法创建下一个令牌,直到a)它从lexer中获得一个备用令牌,b)lexer的
无缓冲harstream
读取它自己的前瞻字符。实际上,它是lexer的一个字符“lag”加上一个标记“lag”

看来,在ANTLR v4中获得“无延迟”的按需数据流意味着编写自己的数据流。但在我看来,现有的数据流工作正常


Antlr是否适合解析来自在要解析的文本之后没有EOF的流的数据

对于ANTLR 4,我还不能自信地回答这个问题。写一个令牌流似乎很容易,直到需要时才进行缓冲(覆盖
无缓冲的令牌流
消费
跳过调用
同步
),但是字符流会被自己读取的类调用
-> 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