Lexer.g4
...
TEST: 'EXEC' -> pushMode (LG2)
...
mode LG2;
...
END_LG2: S_SEMICOLON -> type(S_SEMICOLON), popMode;
...
大多数时候,LG2被用作"岛"语言。但在某些情况下,我也希望能够直接启动 LG2 模式。我可以按如下方式实现:
ANTLRInputStream input = new ANTLRInputStream(...);
PL1Lexer lexer = new PL1Lexer(input);
lexer.pushMode(PL1Lexer.DB2);
问题是在这种情况下,我不希望";"跳回到另一种语言。简而言之:如果我直接从那里开始,我怎么能"停留"在 LG2 语言中?有没有办法"覆盖"规则
END_LG2: S_SEMICOLON -> type(S_SEMICOLON), popMode;
由
ND_LG2: S_SEMICOLON -> type(S_SEMICOLON);
在那种情况下?
您可以重写 Lexer.popMode()
方法以使用自定义行为。不需要这样做的选项将涉及ANTLR 4.4.1即将推出的对零长度令牌的支持。
mode LG2;
// rules here
mode StayInLG2:
ReturnToLG2
: -> skip, pushMode(LG2)
;
然后,您可以在StayInLG2
模式下手动启动。为了响应弹出回StayInLG2
模式,ReturnToLG2
规则不会创建令牌或匹配任何输入,但会LG2
推送回模式堆栈。
PL1Lexer lexer = new PL1Lexer(input);
lexer.mode(StayInLG2);
lexer.pushMode(LG2);
答案看起来不错,但空规则会导致无法禁止显示的警告:
non-fragment lexer rule ReturnToLG2 can match the empty string
因此,对于类似的问题,我使用了覆盖:
@members {
@Override
public int popMode() {
return _modeStack.isEmpty()
? DEFAULT_MODE
: super.popMode();
}
}