如何在ANTLR4中使自动生成的解析器类实现一个接口?

5
我正在使用ANTLR 4创建解析器,并已完成语法。我需要将一些Java代码注入到ANTLR为我自动生成的解析器文件中。
如果我想在生成的解析器中包含一个方法,可以将其添加到ANTLR语法中:
@parser::members
{
  @Override
  public CGrammarParser.CSnippetContext call()
  {
    return cSnippet();
  }
}

如果我想要引入一些导入语句,我可以在语法中添加以下内容:
@header
{
  import java.lang.Thread;
  import java.lang.InterruptedException;
  import java.util.concurrent.Callable;
}

如果我想修改类声明以便实现一个接口,我该怎么做?换句话说,这是ANTLR自动生成的代码:

public class CGrammarParser extends Parser 
{
  ...
}

但这就是我希望它生成的内容:
public class CGrammarParser extends Parser implements Callable<CGrammarParser.CSnippetContext> 
{
  ...
}
2个回答

3
不,不像你描述的那样(通过接口)。但是,您可以定义一个超类,您的解析器应该从中扩展。当然,这个超类应该扩展ANTLR的Parser类。在您自己的(抽象)解析器类中,您可以定义要实现的接口。
以下是如何工作的示例:

CallableParser

import java.util.concurrent.Callable;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.TokenStream;

public abstract class CallableParser extends Parser implements Callable<CGrammarParser.CSnippetContext>
{
    public CallableParser(TokenStream input)
    {
        super(input);
    }
}

CGrammar.g4

grammar CGrammar;

options
{
  superClass = CallableParser;
}

@header
{
  import java.lang.Thread;
  import java.lang.InterruptedException;
  import java.util.concurrent.Callable;
}

@parser::members
{
  @Override
  public CGrammarParser.CSnippetContext call()
  {
    return cSnippet();
  }
}

cSnippet
 : ANY*? EOF
 ;

ANY
 : .
 ;

你也可以采用另一种方式:继承生成的解析器并在派生类中实现所需内容(在我看来,这比使用@parser::members结构更清晰,因为语法和逻辑之间有更多的分离)。仅供参考,对于C#解析器,这个问题的答案甚至更简单:它们是“partial”类。 - Lucas Trzesniewski
我最终开始实现了,但是它不起作用。它抛出了一个 ExceptionInInitializerError 异常。如果我手动添加我想要的 extendsimplements(参见我的问题),它就正常工作。我觉得这个答案非常接近,但是 ANTLR 不满意。 - james.garriss
我尝试了你的答案,@LucasTrzesniewski,它有效!如果你想回答这个问题,我会接受它作为正确答案。谢谢。 - james.garriss

0

这个答案的功劳归于Lucas Trzesniewski

要让你的ANTLR解析器实现一个接口,在语法文件(.g4)中不需要使用Java。只需按照以下步骤操作:

1)创建一个可调用的解析器类,该类扩展了ANTLR解析器并实现了相关接口,例如:

public class CallableParser extends CGrammarParser implements Callable<CGrammarParser.CSnippetContext>
{
    public CallableParser(TokenStream input)
    {
        super(input);
    }

    @Override
    public CGrammarParser.CSnippetContext call()
    {
        return cSnippet();
    }
}

2) 不要调用你的 ANTLR 解析器,而是调用 CallableParser,像这样:

CharStream in = new ANTLRInputStream(input);
CGrammarLexer lexer = new CGrammarLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
// Instead of doing this...
// CGrammarParser parser = new CGrammarParser(tokens);
// Do this...
CallableParser parser = new CallableParser(tokens);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接