Więc zasadniczo chcę powołać poroża produkowane PDDL parsera na plik PDDL od wewnątrz programu Java i mieć go zwrócić obiekt, który opisuje plik PDDL głównego programu Java.
Czy to możliwe?
Pewnie.
Najpierw musisz opisać swój język w pliku gramatycznym (ANTLR). Najłatwiej jest to zrobić w połączeniu gramatyki. Połączona gramatyka stworzy lekser i parser dla Twojego języka. Kiedy język staje się bardziej złożony, lepiej jest oddzielić te dwie, ale na początek łatwiej będzie użyć tylko jednego (połączonego) pliku gramatycznego.
Załóżmy, że język PDDL jest prostym językiem: jest to ciąg jednej lub więcej liczb w zapisie szesnastkowym (0x12FD), ósemkowym (0745) lub dziesiętnym (12345) oddzielonym białymi spacjami. Język ten można opisać w następujący antlr pliku gramatyki zwanego 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;}
;
W tym gramatykę, zasady (analizowania, numer, Hex, ... są zasady), które zaczynają z kapitałem są Lexer-rules. Pozostałe to reguły parsera.
z tej gramatyki, można utworzyć lexer i analizatora składni takiego:
java -cp antlr-3.2.jar org.antlr.Tool PDDL.g
która produkuje (co najmniej) pliki PDDLParser.java
i PDDLLexer.java
.
Teraz utworzyć małą klasę testową, w której można korzystać z tych Lexer i parsera klasy:
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();
}
}
gdzie zawartość pliku source.txt
może wyglądać następująco:
0xcAfE 0234
66678 0X12 0777
Teraz skompilować wszystko .java
pliki:
javac -cp antlr-3.2.jar *.java
i uruchomić główną klasę:
// Windows
java -cp .;antlr-3.2.jar Main
// *nix/MacOS
java -cp .:antlr-3.2.jar Main
Jeśli wszystko pójdzie dobrze, nic nie będzie drukowane na konsoli.
Teraz mówisz, że chcesz, aby analizator składni zwrócił pewne obiekty na podstawie zawartości pliku źródłowego. Załóżmy, że chcemy, aby nasza gramatyka zwróciła wartość List<Integer>
. Można to zrobić poprzez osadzenie „działania” w regułach gramatycznych tak:
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;}
;
Jak widać, można pozwolić zasady zwrotu przedmiotów (returns [Type t]
) i można osadzić zwykły kod Java czy owijanie go w {
i }
. Część w regule parse
jest umieszczana na początku metody parse
w pliku PDDLParser.java
.
Przetestuj nowy parser z tej klasy:
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);
}
}
a zobaczysz co następuje drukowane do konsoli:
After parsing :: [51966, 156, 66678, 18, 511]
+1 Ciekawe pytanie, ale tytuł jest nieco niejasny . Być może uzyskasz więcej informacji za pomocą: "Czy mogę osadzić parser generowany przez Antlr w programie Java, a następnie wywołać go w celu przeanalizowania pliku?" –