7

我是 Antlr 的新手,但之前使用过 Flex/Bison。我想知道我想用 Antlr 做的事情是否可行。

我想使用 Antlr 解析 PDDL 文件,并在解析 PDDL 文件时编写的 Java 类中构建我自己的 PDDL 文件内容表示(在规则的操作中?)。文件解析完成后,我想将文件内容的对象表示返回给 Java 程序以运行其他操作。

因此,本质上,我想从 Java 程序内部对 PDDL 文件调用 Antler 生成的 PDDL 解析器,并让它向主 Java 程序返回一个描述 PDDL 文件的对象。

这可能吗?我试过查看文档,但没有找到好的答案。

非常感谢。

4

2 回答 2

8

因此,本质上,我想从 Java 程序内部对 PDDL 文件调用 Antler 生成的 PDDL 解析器,并让它向主 Java 程序返回一个描述 PDDL 文件的对象。

这可能吗?

当然。

首先,您需要在(ANTLR)语法文件中描述您的语言。最简单的方法是在组合语法中做到这一点。组合语法将为您的语言创建词法分析器和解析器。当语言变得更复杂时,最好将这两者分开,但开始时,只使用一个(组合)语法文件会更容易。

假设 PDDL 语言只是一种简单的语言:它是一个或多个数字的连续,可以是十六进制 (0x12FD)、八进制 (0745) 或十进制 (12345) 符号,由空格分隔。这种语言可以在下面的 ANTLR 语法文件中描述PDDL.g

grammar PDDL;

parse
  :  number+ EOF
  ;

number
  :  Hex
  |  Dec
  |  Oct
  ;

Hex
  :  '0' ('x' | 'X') ('0'..'9' | 'a'..'f' | 'A'..'F')+
  ;

Dec
  :  '0'
  |  '1'..'9' ('0'..'9')*
  ;

Oct
  :  '0' '0'..'7'+
  ;

Space
  :  (' ' | '\t' | '\r' | '\n'){$channel=HIDDEN;}
  ;

在此语法中,以大写字母开头的规则(解析、数字、十六进制……是规则)是词法分析器规则。其他的是解析器规则。

从这个语法中,你可以像这样创建一个词法分析器和解析器:

java -cp antlr-3.2.jar org.antlr.Tool PDDL.g

它产生(至少)文件PDDLParser.javaPDDLLexer.java.

现在创建一个小测试类,您可以在其中使用这些词法分析器和解析器类:

import org.antlr.runtime.*;
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        File source = new File("source.txt");
        ANTLRInputStream in = new ANTLRInputStream(new FileInputStream(source));
        PDDLLexer lexer = new PDDLLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        PDDLParser parser = new PDDLParser(tokens);
        parser.parse();
    }
}

文件的内容source.txt可能如下所示:

0xcAfE 0234
66678 0X12 0777

现在编译所有.java文件:

javac -cp antlr-3.2.jar *.java

并运行主类:

// Windows
java -cp .;antlr-3.2.jar Main

// *nix/MacOS
java -cp .:antlr-3.2.jar Main

如果一切顺利,控制台不会打印任何内容。

现在你说你想让解析器根据你的源文件的内容返回某些对象。假设我们希望我们的语法返回一个List<Integer>. 这可以通过在语法规则中嵌入“动作”来完成,如下所示:

grammar PDDL;

parse returns [List<Integer> list]
@init{$list = new ArrayList<Integer>();}
  :  (number {$list.add($number.value);})+ EOF
  ;

number returns [Integer value]
  :  Hex {$value = Integer.parseInt($Hex.text.substring(2), 16);}
  |  Dec {$value = Integer.parseInt($Dec.text);}
  |  Oct {$value = Integer.parseInt($Oct.text, 8);}
  ;

Hex
  :  '0' ('x' | 'X') ('0'..'9' | 'a'..'f' | 'A'..'F')+
  ;

Dec
  :  '0'
  |  '1'..'9' ('0'..'9')*
  ;

Oct
  :  '0' '0'..'7'+
  ;

Space
  :  (' ' | '\t' | '\r' | '\n'){$channel=HIDDEN;}
  ;

如您所见,您可以让规则返回对象 ( returns [Type t]),并且可以嵌入纯 Java 代码(如果将其包装在{and中) }。规则中的@init部分parse放置在文件中parse方法的PDDLParser.java开头。

用这个类测试新的解析器:

import org.antlr.runtime.*;
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        File source = new File("source.txt");
        ANTLRInputStream in = new ANTLRInputStream(new FileInputStream(source));
        PDDLLexer lexer = new PDDLLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        PDDLParser parser = new PDDLParser(tokens);
        List<Integer> numbers = parser.parse();
        System.out.println("After parsing :: "+numbers);
    }
}

您会看到以下内容被打印到控制台:

After parsing :: [51966, 156, 66678, 18, 511]
于 2010-09-29T08:18:28.557 回答
0

这当然是可能的,因为 Antlr 旨在生成解析器,然后作为更大系统的一部分(例如,编译器或静态代码分析器)调用这些解析器。

从 Terence Parr 的The Definitive Antlr Reference: Building Domain-Specific Languages开始。他是 Antlr 的作者,也是语言处理方面异常清晰且没有行话的老师。

Martin Fowler 的Domain-Specific Languages在很多示例中都使用了 Antlr。例如,在第 200 页上,他展示了一个简单的“Hello World”示例,其中 Java 程序调用 Antlr 来解析要问候的人的文件,并在执行时发出问候。这是完成工作的地方(第 206 页):

class GreetingsLoader. ..
  public void run() {
    try {
      GreetingsLexer lexer = new GreetingsLexer(new ANTLRReaderStream(input));
      GreetingsParser parser = new GreetingsParser(new CommonTokenStream(lexer));
      parser.helper = this;
      parser.script() ;
      if (hasErrors() ) throw new RuntimeException("it all went pear-shaped\n" +
 errorReport() ) ;
    } catch (IOException e) {
      throw new RuntimeException( e) ;
    } catch (RecognitionException e) {
      throw new RuntimeException( e) ;
    }
  }

第三本好书是 Terence 关于 DSL语言实现模式的新书。他描述了使用 Antlr 的各种方法,例如编写抽象语法树生成器以放入编译器。

于 2010-09-29T04:10:15.483 回答