在一个数据流中有两个数据包。每个报头后面都有一些长度未知的二进制数据,直到找到另一个报头或达到EOF。数据如下:HDR12HDR345HDR是头标记12和345为二进制数据。
这是我现在的错误语法:
grammar TEST;
parse : STREAM EOF;
STREAM : PACKET*;
PACKET : HEADER DATA;
HEADER : 'HDR';
DATA : .*;
可以识别第一个报头令牌,但是数据令牌太长,它会消耗下一个报头和数据。
经过三天的寻找,我没有找到任何解决方案,这两个匹配,"二进制数据"one_answers"未知长度"方面。但是我仍然认为这一定是一些常见的解析场景。ANTLR并不像第一眼看上去那么简单:(
感谢您的帮助和建议。
如果没有任何东西直接放在.*
之后,ANTLR将尽可能多地消耗(直到EOF)。所以规则是:
DATA : .*;
应该更改( .*
之后必须有)。
而且,每个词法分析器规则至少应该匹配一个字符。但是您的STREAM
规则可能会匹配空字符串,导致词法分析器创建无限数量的空字符串令牌。
最后,ANTLR用于解析文本输入,而不是二进制数据。在ANTLR邮件列表中查看这个问题,或者在列表中搜索更多信息。
编辑
除了在.*
后面放置一些东西之外,您还可以在词法分析器中执行一些"手动"查找。一个小演示如何告诉ANTLR继续使用字符,直到词法分析器"看到"前面的内容(在您的示例中是"HDR"
):
grammar T;
@parser::members {
public static void main(String[] args) throws Exception {
String input = "HDR1 foo HDR2 bar nn baz HDR3HDR4 the end...";
TLexer lexer = new TLexer(new ANTLRStringStream(input));
TParser parser = new TParser(new CommonTokenStream(lexer));
parser.parse();
}
}
@lexer::members {
private boolean hdrAhead() {
return input.LA(1) == 'H' &&
input.LA(2) == 'D' &&
input.LA(3) == 'R';
}
}
parse : stream EOF;
stream : packet*; // parser rules _can_ match nothing
packet : HEADER DATA? {System.out.println("parsed :: " + $text.replaceAll("\s+", ""));};
HEADER : 'HDR' '0'..'9'+;
DATA : ({!hdrAhead()}?=> .)+;
如果你运行上面的演示:
java -cp antlr-3.3.jar org.antlr.Tool T.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar TParser
(在Windows上,最后一个命令是:java -cp .;antlr-3.3.jar TParser
)
将以下内容打印到控制台:
parsed :: HDR1foo
parsed :: HDR2barbaz
parsed :: HDR3
parsed :: HDR4theend...
表示输入字符串:
HDR1 foo HDR2 bar
baz HDR3HDR4 the end...