如何通过访问者访问ANTLR4中的重复子树?

时间:2013-07-10 06:10:32

标签: antlr4

我无法相信我是第一个提出这个问题的人!使用ANTLR4时,我需要访问者遍历解析树并进行一些修改,因此我需要访问每个树节点中的子树。这是我的Fortran语法的片段:

ifStatement
    : IF_KEYWORD expression
      ( ( THEN_KEYWORD
          executableStatement*
          elseIfStatement*  // <--- problem is here
          elseStatement?
          END_KEYWORD IF_KEYWORD
        ) | executableStatement )
    ;

elseIfStatement
    : ELSE_KEYWORD IF_KEYWORD expression THEN_KEYWORD executableStatement*
    ;

如您所见,elseIfStatement中有重复的子树ifStatement。当我为解析树创建访问者时,我想访问所有被解析的elseIfStatement的上下文:

public Void visitIfStatement(FortranParser.IfStatementContext ctx) {
    ...
    for (FortranParser.ElseIfStatementContext elsIf : ctx.elseIfStatement()) // ERROR!!!
        visitElseIfStatement(elseIf);
    ...
    return null;
}

ctx.elseIfStatement()仅返回第一次出现的elseIfStatement

if (a == 1) then
    a = 2
else if (b == 1) then |
    b = 3             | -> returned by ctx.elseIfStatement()
else if (c == 1) then \
    c = 4             \ -> ignored??
else
    d = 4
end if

那么如何访问所有elseIfStatement子树?此问题适用于所有解析器规则模式,其中“*”为executableStatement*

1 个答案:

答案 0 :(得分:1)

可能是个错误,如果我移除了| executableStatement替代方案,ctx.elseIfStatement() 返回List<ElseIfStatementContext>。您可能想要报告它:https://github.com/antlr/antlr4/issues

但是,正如您现在所做的那样,您将被迫进行一些null检查以查看哪些替代方案匹配。一个更好的方法是"label" your alternatives

ifStatement
 : IF_KEYWORD expression
   THEN_KEYWORD
   executableStatement* 
   elseIfStatement*  
   elseStatement? END_KEYWORD IF_KEYWORD     #ifMultipleStatements
 | IF_KEYWORD expression executableStatement #ifSingleStatement
 ;

将生成以下内容:

public static class IfMultipleStatementsContext extends IfStatementContext {
    ...
    public List<ElseIfStatementContext> elseIfStatement() {
        return getRuleContexts(ElseIfStatementContext.class);
    }
    ...
}

即:它会生成适当数量的ElseIfStatementContext s。