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

如何通过访问者访问ANTLR4中的重复子树?,antlr4,Antlr4,我不敢相信我是第一个问这个问题的人!在使用ANTLR4时,我需要一个访问者遍历解析树并进行一些修改,因此我需要访问每个树节点中的子树。以下是我的Fortran语法片段: ifStatement : IF_KEYWORD expression ( ( THEN_KEYWORD executableStatement* elseIfStatement* // <--- problem is here elseSt

我不敢相信我是第一个问这个问题的人!在使用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*
    ;
但是
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*
的解析器规则模式。

可能是一个bug,如果我删除
|executableStatement
替代项,
ctx.elseIfStatement()
会返回一个
列表。您可能要报告它:

但是,当您现在这样做时,您将被迫执行一些
null
检查,以查看哪个选项匹配。更好的方法是:

这将产生以下结果:

public static class IfMultipleStatementsContext extends IfStatementContext {
    ...
    public List<ElseIfStatementContext> elseIfStatement() {
        return getRuleContexts(ElseIfStatementContext.class);
    }
    ...
}
公共静态类ifmultipleStatementContext扩展了IfStatementContext{
...
公共列表其他声明(){
返回getRuleContext(ElseIfStatementContext.class);
}
...
}

也就是说:它生成了适量的
ElseIfStatementContext
s.

可能是一个bug,如果我删除
| executableStatement
替代项,
ctx.elseIfStatement()
会返回一个
列表。您可能要报告它:

但是,当您现在这样做时,您将被迫执行一些
null
检查,以查看哪个选项匹配。更好的方法是:

这将产生以下结果:

public static class IfMultipleStatementsContext extends IfStatementContext {
    ...
    public List<ElseIfStatementContext> elseIfStatement() {
        return getRuleContexts(ElseIfStatementContext.class);
    }
    ...
}
公共静态类ifmultipleStatementContext扩展了IfStatementContext{
...
公共列表其他声明(){
返回getRuleContext(ElseIfStatementContext.class);
}
...
}

即:它生成适量的
ElseIfStatementContext
s.

Bart,谢谢您的帮助!我听从了你的建议,并在
类IfMultipleStatementsContext
中获得了
公共列表elseIfStatement()
。我想ANTLR4不喜欢我以前的规则风格?无论如何,我会报告这个问题。我还有一个问题。既然我们已经标记了替代规则,那么如果我们有另一个规则包含
ifStatement
,那么我们如何着手处理
ifmultiplestatement
ifSingleStatement
。我在
IfStatementContext
类中没有看到它们。@LiDong,我没有测试它,但我想你应该将
IfStatementContext
转换为
ifmultiplestatementcontext
IfSingleStatementContext
。我怎么知道应该转换哪一个呢?通过检查一些子树的存在?谢谢@李东,我想你在施展之前需要在
IfStatementContext
上有一个(不太漂亮的)
instanceof
。巴特,谢谢你的帮助!我听从了你的建议,并在
类IfMultipleStatementsContext
中获得了
公共列表elseIfStatement()
。我想ANTLR4不喜欢我以前的规则风格?无论如何,我会报告这个问题。我还有一个问题。既然我们已经标记了替代规则,那么如果我们有另一个规则包含
ifStatement
,那么我们如何着手处理
ifmultiplestatement
ifSingleStatement
。我在
IfStatementContext
类中没有看到它们。@LiDong,我没有测试它,但我想你应该将
IfStatementContext
转换为
ifmultiplestatementcontext
IfSingleStatementContext
。我怎么知道应该转换哪一个呢?通过检查一些子树的存在?谢谢@李东,我想你在施放之前需要在
IfStatementContext
上有一个(不太漂亮的)
instanceof
public static class IfMultipleStatementsContext extends IfStatementContext {
    ...
    public List<ElseIfStatementContext> elseIfStatement() {
        return getRuleContexts(ElseIfStatementContext.class);
    }
    ...
}