antlr4语法迭代解析来自单个InputStream的重复内容



我有一个包含重复块的InputStream:

fld1:val1
fld2:val2
[A B C D]
[E F]
fld1:val3
fld2:val4
[M N]
[Q S T Y]
fld1:val5
...

我希望构建一个解决方案,其中我可以解析fld:val块,跳过空白行分隔符,然后解析"listy"部分,然后在下一个空白行停止解析,并在相同的打开流上重置解析器以处理下一个块。我想我可能能够通过访问解析器并调用reset()来覆盖基本侦听器类exitListy回调。理想情况下,这将结束对ParseTree t = parser.parse()的调用链,并让控制立即返回到parse()之后的代码。我对此进行了实验,并且在某种程度上可以预见,在这里得到了一个空指针异常:org.antlr.v4.runtime.Parser.exitRule(Parser.java:639)我不能改变输入流的格式,例如插入片段标记或类似的任何东西。

(基于评论的全新答案)

侦听器对解析完成后返回的parsetree进行操作。在您的情况下,它似乎是,您将监听一个本质上是无止境的流,并希望定期返回数据。

我强烈推荐《The Definitive ANTLR 4 reference》。

有两个非常相关的部分:

  • <<解析过程中发生的事情>
  • "未缓冲的字符和令牌流">

对于你的语法,尝试类似于下面的"草稿"。(这可能不会在您想要的时候准确地报告,但希望能给您提供工作的想法)

grammar Streaming;
@parser::members {
java.util.function.Consumer<MyData> consumer;
MyData myData = new MyData();
public StreamingParser(TokenStream input, java.util.function.Consumer<MyData> consumer) {
this(input);
this.consumer = consumer;
}
}
stream: (fldLine emptyLine listLine emptyLine) EOF;
fldLine:
fld = ITEM COLON val = ITEM EOL {
// add data to MyDataObject
};
listLine:
O_BRACKET (items = ITEM)* C_BRACKET {
// add data to MyDataObject
};
emptyLine:
EOL {
consumer.accept(myData);
// reset myData
};
O_BRACKET: '[';
C_BRACKET: ']';
EOL: 'n';
COLON: ':';
ITEM: [a-zA-Z][a-zA-Z0-9]*;
SPACE: ' ' -> skip;

这利用了第一节中描述的嵌入式操作。

然后第二部分描述了如何使用Unbuffered流。

类似这样的内容(未经测试;许多内容直接摘自参考书)

CharStream input = new UnbufferedCharStream(<your stream>);
StreamingLexer lex = new StreamingLexer(input);
lex.setTokenFactory(new CommonTokenFactory(true));
TokenStream tokens = new UnbufferedTokenStream<CommonToken>(lex);
StreamingParser parser = new StreamingParser(tokens,
// This lambda will handle data reported back when a blank line is encountered
myData -> handle(myData));
// You just want ANTLR reporting back periodically
// not building a giant parse tree
parser.setBuildParseTree(false); 
parser.stream();  // won't return until you shut down the input stream

最新更新