2013-07-10 71 views
1

我不敢相信我是第一个问这个问题的人!当使用ANTLR4时,我需要访问者遍历分析树并进行一些修改,所以我需要访问每个树节点中的子树。这里是我的Fortran语法的一个片段:如何通过访问者访问ANTLR4中的重复子树?

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

正如你所看到的,有在ifStatement重复子树elseIfStatement。当我创建解析树访问者,我想访问被解析的所有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

可能是一个错误,如果我删除了| 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上的适当量。

+0

巴特,感谢您的帮助!我遵循你的建议,并在'class IfMultipleStatementsContext'中得到了'public List elseIfStatement()'。我认为ANTLR4不喜欢我以前的规则风格?无论如何我会报告这个问题。 –

+0

@LiDong,不客气。 –

+0

我还有一个问题。由于我们已经标记了其他规则,如果我们有另一个规则包含'ifStatement',那么我们该如何回到'ifMultipleStatements'或'ifSingleStatement'。我在IfStatementContext类中看不到它们。 –