[英]Can I use an Antlr created lexer/parser to parse PDDL file and return data to a Java program?
我是Antlr的新手,但之前使用过Flex / Bison。 我想知道使用Antlr我想做什么是可能的。
我想使用Antlr解析PDDL文件,并在解析PDDL文件时编写的Java类中构建我自己的PDDL文件内容表示(在规则的操作中?)。 在文件完成解析之后,我想将文件内容的对象表示返回给Java程序以运行其他操作。
基本上,我想从Java程序内部在PDDL文件上调用Antler生成的PDDL解析器,并让它返回一个描述PDDL文件到主Java程序的对象。
这可能吗? 我试过看文档,但没有找到一个好的答案。
非常感谢。
基本上,我想从Java程序内部在PDDL文件上调用Antler生成的PDDL解析器,并让它返回一个描述PDDL文件到主Java程序的对象。
这可能吗?
当然。
首先,您需要在(ANTLR)语法文件中描述您的语言。 最简单的方法是使用组合语法。 组合语法将为您的语言创建词法分析器和解析器。 当语言变得更复杂时,最好将这两者分开,但首先,只使用一个(组合的)语法文件会更容易。
假设PDDL语言只是一种简单的语言:它是由十六进制(0x12FD),八进制(0745)或十进制(12345)表示的一个或多个数字的连续,用空格分隔。 可以在以下名为PDDL.g
ANTLR语法文件中描述该语言:
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.java
和PDDLLexer.java
。
现在创建一个小测试类,您可以在其中使用这些lexer和parser类:
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>
。 这可以通过在你的语法规则中嵌入“actions”来完成,如下所示:
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代码。 parse
规则中的@init
部分放在PDDLParser.java
文件中的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]
这当然是可能的,因为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的各种方法,例如编写一个抽象语法树生成器以放入编译器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.