How to use antlr4 in Eclipse?
Asked Answered
D

2

6

Since Antlr4 is new version of Antlr and this is the first time I use it. I have downloaded the Antlr4 plugin from eclipse marketplace. I made new ANTLR 4 project and I got Hello.g4

Afterward I saw this small grammar:

  /**
  * Define a grammar called Hello
   */
   grammar Hello;
     r  : 'hello' ID ;         // match keyword hello followed by an                                                          identifier

      ID : [a-z]+ ;             // match lower-case identifiers

       WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines

Once it was saved, It was build and I saw it from the Antlr console, I wanted to test the program but I didn't know how, and I didn't know how to make a new file that can be compiled by the new grammar?

Thanks in advance for any help.

Docilla answered 5/2, 2015 at 19:16 Comment(0)
E
10

You need to create an instance of the generated parser in order to run it.

  • Create a Java project J next to your ANTLR project A.
  • Create a linked folder in project J referencing the generated-sources/antlr4 folder from A, and make this linked folder a source folder. Compile errors should appear.
  • Add the antlr4 jar to the build path of project J. This should remove the compile errors.
  • Write a main program in J which creates an instance of the generated parser and feeds it with text. You can take the TestRig from the ANTLR documentation, pasted below for convenience.

The TestRig must be invoked by passing the grammar name (Hello, in your example) and the starting rule (r).

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.DefaultErrorStrategy;
import org.antlr.v4.runtime.DiagnosticErrorListener;
import org.antlr.v4.runtime.InputMismatchException;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.atn.PredictionMode;

import javax.print.PrintException;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/** Run a lexer/parser combo, optionally printing tree string or generating
 *  postscript file. Optionally taking input file.
 *
 *  $ java org.antlr.v4.runtime.misc.TestRig GrammarName startRuleName
 *        [-tree]
 *        [-tokens] [-gui] [-ps file.ps]
 *        [-trace]
 *        [-diagnostics]
 *        [-SLL]
 *        [input-filename(s)]
 */
public class Test {
    public static final String LEXER_START_RULE_NAME = "tokens";

    protected String grammarName;
    protected String startRuleName;
    protected final List<String> inputFiles = new ArrayList<String>();
    protected boolean printTree = false;
    protected boolean gui = false;
    protected String psFile = null;
    protected boolean showTokens = false;
    protected boolean trace = false;
    protected boolean diagnostics = false;
    protected String encoding = null;
    protected boolean SLL = false;

    public Test(String[] args) throws Exception {
        if ( args.length < 2 ) {
            System.err.println("java org.antlr.v4.runtime.misc.TestRig GrammarName startRuleName\n" +
                               "  [-tokens] [-tree] [-gui] [-ps file.ps] [-encoding encodingname]\n" +
                               "  [-trace] [-diagnostics] [-SLL]\n"+
                               "  [input-filename(s)]");
            System.err.println("Use startRuleName='tokens' if GrammarName is a lexer grammar.");
            System.err.println("Omitting input-filename makes rig read from stdin.");
            return;
        }
        int i=0;
        grammarName = args[i];
        i++;
        startRuleName = args[i];
        i++;
        while ( i<args.length ) {
            String arg = args[i];
            i++;
            if ( arg.charAt(0)!='-' ) { // input file name
                inputFiles.add(arg);
                continue;
            }
            if ( arg.equals("-tree") ) {
                printTree = true;
            }
            if ( arg.equals("-gui") ) {
                gui = true;
            }
            if ( arg.equals("-tokens") ) {
                showTokens = true;
            }
            else if ( arg.equals("-trace") ) {
                trace = true;
            }
            else if ( arg.equals("-SLL") ) {
                SLL = true;
            }
            else if ( arg.equals("-diagnostics") ) {
                diagnostics = true;
            }
            else if ( arg.equals("-encoding") ) {
                if ( i>=args.length ) {
                    System.err.println("missing encoding on -encoding");
                    return;
                }
                encoding = args[i];
                i++;
            }
            else if ( arg.equals("-ps") ) {
                if ( i>=args.length ) {
                    System.err.println("missing filename on -ps");
                    return;
                }
                psFile = args[i];
                i++;
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Test test = new Test(args);
        if(args.length >= 2) {
            test.process();
        }
    }

    public void process() throws Exception {
        //System.out.println("exec "+grammarName+" "+startRuleName);
        String lexerName = grammarName+"Lexer";
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        Class<? extends Lexer> lexerClass = null;
        try {
            lexerClass = cl.loadClass(lexerName).asSubclass(Lexer.class);
        }
        catch (java.lang.ClassNotFoundException cnfe) {
                System.err.println("1: Can't load "+lexerName+" as lexer or parser");
                return;
        }

        Constructor<? extends Lexer> lexerCtor = lexerClass.getConstructor(CharStream.class);
        Lexer lexer = lexerCtor.newInstance((CharStream)null);

        Class<? extends Parser> parserClass = null;
        Parser parser = null;
        if ( !startRuleName.equals(LEXER_START_RULE_NAME) ) {
            String parserName = grammarName+"Parser";
            parserClass = cl.loadClass(parserName).asSubclass(Parser.class);
            if ( parserClass==null ) {
                System.err.println("Can't load "+parserName);
            }
            Constructor<? extends Parser> parserCtor = parserClass.getConstructor(TokenStream.class);
            parser = parserCtor.newInstance((TokenStream)null);
        }

        if ( inputFiles.size()==0 ) {
            InputStream is = System.in;
            Reader r;
            if ( encoding!=null ) {
                r = new InputStreamReader(is, encoding);
            }
            else {
                r = new InputStreamReader(is);
            }

            process(lexer, parserClass, parser, is, r);
            return;
        }
        for (String inputFile : inputFiles) {
            InputStream is = System.in;
            if ( inputFile!=null ) {
                is = new FileInputStream(inputFile);
            }
            Reader r;
            if ( encoding!=null ) {
                r = new InputStreamReader(is, encoding);
            }
            else {
                r = new InputStreamReader(is);
            }

            if ( inputFiles.size()>1 ) {
                System.err.println(inputFile);
            }
            process(lexer, parserClass, parser, is, r);
        }
    }

    protected void process(Lexer lexer, Class<? extends Parser> parserClass, Parser parser, InputStream is, Reader r) throws IOException, IllegalAccessException, InvocationTargetException, PrintException {
        try {
            ANTLRInputStream input = new ANTLRInputStream(r);
            lexer.setInputStream(input);
            CommonTokenStream tokens = new CommonTokenStream(lexer);

            tokens.fill();

            if ( showTokens ) {
                for (Object tok : tokens.getTokens()) {
                    System.out.println(tok);
                }
            }

            if ( startRuleName.equals(LEXER_START_RULE_NAME) ) return;

            if ( diagnostics ) {
                parser.addErrorListener(new DiagnosticErrorListener());
                parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);
            }

            if ( printTree || gui || psFile!=null ) {
                parser.setBuildParseTree(true);
            }

            if ( SLL ) { // overrides diagnostics
                parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
            }

            parser.setTokenStream(tokens);
            parser.setTrace(trace);
            //parser.setErrorHandler(new BailErrorStrategy());

            try {
                Method startRule = parserClass.getMethod(startRuleName);
                ParserRuleContext tree = (ParserRuleContext)startRule.invoke(parser, (Object[])null);

                if ( printTree ) {
                    System.out.println(tree.toStringTree(parser));
                }
                if ( gui ) {
                    tree.inspect(parser);
                }
                if ( psFile!=null ) {
                    tree.save(parser, psFile); // Generate postscript
                }
            }
            catch (NoSuchMethodException nsme) {
                System.err.println("No method for rule "+startRuleName+" or it has arguments");
            }
        }
        finally {
            if ( r!=null ) r.close();
            if ( is!=null ) is.close();
        }
    }

  @SuppressWarnings("unused")
  private static class BailErrorStrategy extends DefaultErrorStrategy {
      /** Instead of recovering from exception e, rethrow it wrapped
      * in a generic RuntimeException so it is not caught by the
      * rule function catches. Exception e is the "cause" of the
      * RuntimeException.
      */
      @Override
      public void recover(Parser recognizer, RecognitionException e) {
      throw new RuntimeException(e);
      }
      /** Make sure we don't attempt to recover inline; if the parser
      * successfully recovers, it won't throw an exception.
      */
      @Override
      public Token recoverInline(Parser recognizer)
      throws RecognitionException
      {
      throw new RuntimeException(new InputMismatchException(recognizer));
      }
      /** Make sure we don't attempt to recover from problems in subrules. */
      @Override
      public void sync(Parser recognizer) { }
      }
}

'Hope this helps!

Estrada answered 6/2, 2015 at 10:7 Comment(2)
Thank you but I got a runtime error from console that says: java org.antlr.v4.runtime.misc.TestRig GrammarName startRuleName [-tokens] [-tree] [-gui] [-ps file.ps] [-encoding encodingname] [-trace] [-diagnostics] [-SLL] [input-filename(s)] Use startRuleName='tokens' if GrammarName is a lexer grammar. Omitting input-filename makes rig read from stdin.Docilla
Did you provide command-line arguments ? In Eclipse, the "Run Configuration" window has an "(x) Arguments" tab, which has a "Program Arguments" field where you can provide command-line arguments. In your case, you probably need : Hello r <your-file-name>.Estrada
S
0
  1. Create a new ANTLR 4 Project
  2. Convert the project to faceted form
  3. Add Java project facet
  4. Optionally you can add package names to be generated in the header of the grammar file
  5. Use target/generated-sources/antlr4 as source folder
  6. Edit and save the grammar file to re-generate everything

The antlr4 generated sources should now be packaged and imported as usual inside your project.

Salters answered 19/9, 2019 at 17:52 Comment(3)
How is step 4 done? It seems the package definition with annotations is not available in version 4.Flaky
Step 4 can be skipped. I can't recall now how but I remember generating antlr sources in the header package. Check last section of the following link to see if it helps: github.com/antlr/antlr4/blob/master/doc/grammars.mdSalters
@Flaky Step 4 - add to the head of your grammar .g4 file : @header { package your.package.name; } Waterlog

© 2022 - 2024 — McMap. All rights reserved.