在Antlr 4中对同一访客进行重复评价。

问题描述 投票:1回答:1

我使用语法建立了一个Antlr 4过滤器(在这里的上下文中不重要),过滤器看起来像 "年龄> 30 AND身高< 6.1"。

然而,问题是,我将建立一次这个过滤器,并使用它来评估大概一千个文档。每个文档都会有一个 "年龄 "和 "身高 "属性。

然而我不确定的是,如何重用parser或lexer,以便我可以加快评估速度。每次都建立一个lexer &&解析器似乎真的很浪费时间。

java代码是这样的

  public Boolean createFilterVisitor(String input, DocFieldAccessor docFieldAccessor) {
    FilterLexer lexer = new FilterLexer(CharStreams.fromString(input));
    lexer.removeErrorListener(ConsoleErrorListener.INSTANCE);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    FilterParser parser = new FilterParser(tokens);
    parser.addErrorListener(new FilterErrorListener());
    parser.removeErrorListener(ConsoleErrorListener.INSTANCE);

    FilterVisitorImpl filterVisitor = new FilterVisitorImpl(docFieldAccessor);

    return filterVisitor.visit(parser.filter());
  }

然后

for doc in docs:
  createFilterVisitor(doc, someAccessor);

我试着构建一次lexer和parser,然后在循环的开始处做lexer.reset()和parser.reset()。这似乎是可行的(它能过滤合理的文档),但我真的不确定我的做法是否正确。我不知道reset是什么意思,也不知道什么时候应该使用它。

所以我的问题是。

  1. 我如何解析过滤字符串,并建立一个解析器,而不是为每个文档建立一个解析器?
  2. 我是否正确使用了reset?

我有这样的代码。这能用吗?

public class KalaFilter {
  private final String filterClause;
  private FilterLexer lexer;
  private FilterParser parser;

  @Getter
  private final FilterAnalyzer filterAnalyzer;

  public KalaFilter(String filterClause) {
    this.filterClause = filterClause;

    lexer = new FilterLexer(CharStreams.fromString(filterClause));

    lexer.removeErrorListener(ConsoleErrorListener.INSTANCE);
    CommonTokenStream tokens = new CommonTokenStream(lexer);

    parser = new FilterParser(tokens);
    parser.addErrorListener(new FilterErrorListener());
    parser.removeErrorListener(ConsoleErrorListener.INSTANCE);

    ParseTree parseTree = parser.filter();

    filterAnalyzer = new FilterAnalyzer();
    ParseTreeWalker walker = new ParseTreeWalker(); // create standard walker

    walker.walk(filterAnalyzer, parseTree);
  }

  // return filter result by visit parser
  public Boolean visitFitlerResult(DocFieldAccessor docFieldAccessor) {
    //lexer.reset();
    //FilterLexer lexer = new FilterLexer(CharStreams.fromString(filterClause));
    /*
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    FilterParser parser = new FilterParser(tokens);
    parser.addErrorListener(new FilterErrorListener());
    parser.removeErrorListener(ConsoleErrorListener.INSTANCE);
     */

    parser.reset();
    FilterVisitorImpl filterVisitor = new FilterVisitorImpl(docFieldAccessor);
    return filterVisitor.visit(parser.filter());
  }
}
java parsing antlr antlr4
1个回答
5
投票

你的代码的布局方式,你传递了一个字符串到构造函数,在构造函数中解析这个字符串,然后每次都再次解析那个完全相同的字符串。visitFilterResult 的调用。除非你在你的语法操作中做了一些非常不寻常的事情,否则每次解析同一个字符串都应该产生完全相同的结果,所以没有理由重复解析同一个字符串,而不是仅仅重复使用结果。

因此,我们不应该将字符串、词法器和解析器作为实例变量来存储,而应该将调用 parser.filter();. 然后不调用 visitFilterResult你可以使用现有的解析树并在其上调用访问者。这样就不需要重置任何东西,因为解析器只被调用一次(在构造函数中)。

© www.soinside.com 2019 - 2024. All rights reserved.