我多年来一直试图创建一个实现GrammarASTVisitor
的访问者。
我在Grammar
对象上加载语法规则:
final Grammar g = Grammar.load("....dslGrammar.g4");
之后,我正在尝试使用AST
接口的实现来访问语法GrammarASTVisitor
:
public class DSLGrammarVisitor implements GrammarASTVisitor {
@Override
public Object visit(GrammarAST node)
{
}
@Override
public Object visit(GrammarRootAST node)
{
return null;
}
@Override
public Object visit(RuleAST node)
{
return null;
}
@Override
public Object visit(BlockAST node)
{
return null;
}
@Override
public Object visit(OptionalBlockAST node)
{
return null;
}
@Override
public Object visit(PlusBlockAST node)
{
return null;
}
@Override
public Object visit(StarBlockAST node)
{
return null;
}
@Override
public Object visit(AltAST node)
{
return null;
}
@Override
public Object visit(NotAST node)
{
return null;
}
@Override
public Object visit(PredAST node)
{
return null;
}
@Override
public Object visit(RangeAST node)
{
return null;
}
@Override
public Object visit(SetAST node)
{
return null;
}
@Override
public Object visit(RuleRefAST node)
{
return null;
}
@Override
public Object visit(TerminalAST node)
{
return null;
}
}
因此,在从文件加载语法后,我这样做:
GrammarASTVisitor v = new GrammarASTVisitorImpl();
g.ast.visit(v)
之后,执行visit(grammarRootAST)
方法。然而,我刚刚意识到我无法弄清楚如何访问这些孩子。我不太清楚如何让孩子AST节点保持其类型。
我已尝试使用node.getChildren()
,但它会返回List<? extends Object>
,因此visit(Object)
上没有GrammarASTVisitor
方法来实现visit(Object)
。
我也尝试使用node.getChildrenAsArray()
但是,每个项目都是GrammarAST
个节点,而不是RuleAST
,SetAST
,TerminalAST
等等...
有什么想法吗?
答案 0 :(得分:1)
不幸的是,Java不支持双重调度。您必须手动覆盖访问(GrammarAST节点),该访问按节点的类切换并调度到适当的方法。实际上他们应该给出一些抽象的类,但它不存在。
所以基本上类似下面的代码(用xtend编写,但你可以把它转换成java)应该可以做到这一点:
GrammarASTVisitor() {
override visit(GrammarAST node) {
node.children?.forEach[
switch(it) {
case RuleAST: visit(it as RuleAST)
case BlockAST: visit(it as BlockAST)
case OptionalBlockAST: visit(it as OptionalBlockAST)
case PlusBlockAST: visit(it as PlusBlockAST)
case StarBlockAST: visit(it as StarBlockAST)
case AltAST: visit(it as AltAST)
case NotAST: visit(it as NotAST)
case PredAST: visit(it as PredAST)
case RangeAST: visit(it as RangeAST)
case SetAST: visit(it as SetAST)
case RuleRefAST: visit(it as RuleRefAST)
case TerminalAST: visit(it as TerminalAST)
default: visit(it as GrammarAST)
}
]
node
}
override visit(GrammarRootAST node) {
node.children?.forEach[this.visit(it as GrammarAST)]
node
}
...