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);
在那种情况下?
答案 0 :(得分:1)
您可以覆盖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);
答案 1 :(得分:0)
接受的答案看起来不错,但空规则会产生无法抑制的警告:
non-fragment lexer rule ReturnToLG2 can match the empty string
因此,对于类似的问题,我选择了覆盖:
@members {
@Override
public int popMode() {
return _modeStack.isEmpty()
? DEFAULT_MODE
: super.popMode();
}
}