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