强制ANTLR在解析器中使用我的自定义TreeAdaptor

时间:2012-06-25 17:41:12

标签: constructor antlr

ANTLR解析器生成以下生成的代码:

protected TreeAdaptor adaptor = new CommonTreeAdaptor();

我已经实现了自己的TreeAdaptor,我希望解析器始终使用我的并且永远不会使用CommonTreeAdaptor()。我发现的唯一方法是每次创建新的解析器时将其设置在调用代码中:

Parser parser = new MyParser();
parser.setTreeAdaptor(new MyAdaptor());

我是否可以通过某种方式设置默认的TreeAdaptor或将一些初始化代码附加到生成的构造函数中?

2 个答案:

答案 0 :(得分:2)

  

我是否可以通过某种方式设置默认的TreeAdaptor或将一些初始化代码附加到生成的构造函数中?

一种方法是添加一个静态方法来设置自定义树适配器:

grammar T;

options {
  output=AST;
  ASTLabelType=CommonTree;
}

@parser::members {

  public static TParser newTParser(TreeNodeStream input) {
    TParser parser = new TParser(input);
    parser.setTreeAdaptor(new MyAdaptor());
    return parser;
  }
}

parse
 : Any* EOF
 ;

Any
 : .
 ;

然后你可以替换:

TParser parser = new TParser(input);

TParser parser = TParser.newTParser(input);

答案 1 :(得分:0)

我认为我找到了比Bart的命名构造方法更好的解决方案。

我无法直接修改生成的构造函数(包括将其设为私有,这就是我不喜欢named-constructor解决方案的原因)。但是,我可以介绍一个初始化块:

grammar T;

options {
  output=AST;
  ASTLabelType=CommonTree;
}

@parser::members {
    {
        this.adaptor = new MyAdaptor();
    }
}

根据Java documentation,“Java编译器将初始化程序块复制到每个构造函数中。因此,这种方法可用于在多个构造函数之间共享代码块。”

因此this.adaptor首先会被生成的代码设置为new CommonTreeAdaptor(),但我的初始化块会将其设置为new MyAdaptor()。测试证实这就是实际发生的事情。

这个解决方案的优点是我的解析器的调用者不需要知道它使用自定义的TreeAdaptor或做任何不寻常的事情(我的适配器是CommonTreeAdaptor的子类,所以任何依赖于它的代码都是细)。