james.garriss
james.garriss

Reputation: 13397

How do I make the auto-generated parser class implement an interface in ANTLR4?

I am using ANTLR 4 to create a parser, and I have completed my grammar. I need to inject some Java code into the resulting parser file that ANTLR auto-generates for me.

If I want to include a method in the resulting parser, I can add this to the ANTLR grammar:

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

If I want to include some import statements, I can add this to the grammar:

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

If I want to modify the class declaration so that it implements an interface, how do I do that? In other words, this is what ANTLR auto-generates:

public class CGrammarParser extends Parser 
{
  ...
}

But this is what I want it to generate:

public class CGrammarParser extends Parser implements Callable<CGrammarParser.CSnippetContext> 
{
  ...
}

Upvotes: 5

Views: 2619

Answers (2)

james.garriss
james.garriss

Reputation: 13397

Credit for this answer goes to Lucas Trzesniewski.

To have your ANTLR parser implement an interface, no Java is required in the grammar file (.g4) itself. Simply do the following:

1) Create an callable parser class that extends the ANTLR parser and implements the interface in question, something like:

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

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

2) Instead of calling your ANTLR parser, call the CallableParser instead, like this:

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);

Upvotes: 0

Bart Kiers
Bart Kiers

Reputation: 170158

No, not like you describe (via interface(s)). However, you can define a super class your parser should extend from. This super class should, of course, extend ANTLR's Parser class. In your own (abstract) parser class, you then define the interfaces you want to implement.

Here's how that could work:

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
 : .
 ;

Upvotes: 3

Related Questions