为了让ANTLR4的词法分析器在一个规则中识别不同类型的令牌,我使用语义谓词。该谓词评估辅助类的静态字段。看看一些语法摘录:
// very simplified
@header {
import static ParserAndLexerState.*;
}
@members {
private boolean fooAllowed() {
System.out.println(fooAllowed);
}
...
methodField
: t = type
{ fooAllowed = false; }
id = Identifier
{ fooAllowed = true; /* do something with t and id*/ }
...
fragment CHAR_NO_OUT_1 : [a-eg-zA-Z_] ;
fragment CHAR_NO_OUT_2 : [a-nq-zA-Z_0-9] ;
fragment CHAR_NO_OUT_3 : [a-nq-zA-Z_0-9] ;
fragment CHAR_1 : [a-zA-Z_] ;
fragment CHAR_N : CHAR_1 | [0-9] ;
Identifier
// returns every possible identifier
: { fooAllowed() }? (CHAR_1 CHAR_N*)
// returns everything but 'foo'
| { !fooAllowed() }? CHAR_NO_OUT_1 (CHAR_NO_OUT_2 (CHAR_NO_OUT_3 CHAR_N*)?)? ;
Identifier
现在的行为似乎fooAllowed
具有ParserAndLexerState
中定义的初始值。因此,如果这是真的Identifier
将只使用规则的第一个替代,否则总是第二个。这是一些奇怪的行为,特别是考虑到fooAllowed
将正确的值输出到控制台。
ANTLR4中有什么东西可以阻止我在语义谓词中使用全局状态吗?我该如何避免这种行为?
答案 0 :(得分:0)
ANTLR 4使用具有非确定性终止条件的无界前瞻预测过程。虽然TokenStream
实现会懒惰地调用TokenSource.nextToken
,但是假设到目前为止所消耗的令牌数量有限是不安全的。
换句话说,使用解析器操作来改变词法分析器行为的实际语义是未定义的。不同版本的ANTLR 4,或者你输入的输入中的细微变化,都会产生完全不同的结果。