antlr4 - 如何"覆盖"一个popMode?

时间:2014-10-08 07:24:01

标签: antlr4

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);

在那种情况下?

2 个答案:

答案 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();
    }
}