如何在Eclipse中使用antlr4?

5

由于Antlr4是Antlr的新版本,这是我第一次使用它。我从Eclipse Marketplace下载了Antlr4插件。我创建了一个新的ANTLR 4项目,并得到了Hello.g4。

接着我看到了这个小语法:

  /**
  * 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

一旦保存后,进行构建并从Antlr控制台中查看,我想测试程序但不知道如何操作,也不知道如何创建一个可以由新语法编译的新文件?
提前感谢您的任何帮助。
2个回答

9

为了运行生成的解析器,您需要创建一个实例。

  • 在ANTLR项目A旁边创建一个Java项目J。
  • 在项目J中创建一个链接文件夹,引用从A中的generated-sources/antlr4文件夹,并将此链接文件夹设置为源文件夹。编译错误应该会出现。
  • 将antlr4 jar添加到项目J的构建路径中。这应该可以消除编译错误。
  • 在J中编写一个主程序,创建生成的解析器的一个实例并将其提供给文本。您可以从ANTLR文档中获取TestRig,下面是方便起见粘贴的代码:

必须通过传递语法名称(在您的示例中为Hello)和起始规则(r)来调用TestRig。

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) { }
      }
}

希望这能帮到你!

谢谢,但是我从控制台收到一个运行时错误,内容如下:java org.antlr.v4.runtime.misc.TestRig GrammarName startRuleName [-tokens] [-tree] [-gui] [-ps file.ps] [-encoding encodingname] [-trace] [-diagnostics] [-SLL] [input-filename(s)] 如果GrammarName是词法分析器语法,则使用startRuleName='tokens'。 省略input-filename则rig从stdin读取。 - Naji Kadri
你提供了命令行参数吗?在Eclipse中,“运行配置”窗口有一个“(x) Arguments”选项卡,其中有一个“程序参数”字段,您可以在其中提供命令行参数。在您的情况下,您可能需要:Hello r <your-file-name> - Marc Q.

0
  1. 创建一个新的ANTLR 4项目
  2. 将项目转换为多面体形式
  3. 添加Java项目方面
  4. 可选地,您可以在语法文件头中添加要生成的包名称
  5. 使用target/generated-sources/antlr4作为源文件夹
  6. 编辑并保存语法文件以重新生成所有内容

antlr4生成的源现在应该像往常一样打包和导入到您的项目中。


第四步怎么做?似乎版本4中没有带注释的包定义。 - z3rone
1
第四步可以跳过。我现在记不清楚了,但我记得在头文件包中生成antlr源代码。请查看以下链接的最后一节,看看是否有帮助:https://github.com/antlr/antlr4/blob/master/doc/grammars.md - lainatnavi
1
@z3rone 第四步 - 在您的语法.g4文件的头部添加以下内容: - Lorenzo

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