Chciałbym zacząć od ANTLR, ale po spędzeniu kilku godzin na przejrzeniu przykładów na stronie antlr.org nadal nie mogę dobrze zrozumieć gramatyki języka Java.
Czy istnieje jakiś prosty przykład, coś w rodzaju kalkulatora czterech operacji zaimplementowanego z ANTLR przechodzącym przez definicję parsera aż do kodu źródłowego Java?
Odpowiedzi:
Uwaga : ta odpowiedź dotyczy ANTLR3 ! Jeśli szukasz przykładu ANTLR4 , to pytania i odpowiedzi pokazują, jak utworzyć prosty analizator składni wyrażeń i ewaluatora używającego ANTLR4 .
Najpierw tworzysz gramatykę. Poniżej znajduje się mała gramatyka, której można użyć do oceny wyrażeń zbudowanych przy użyciu 4 podstawowych operatorów matematycznych: +, -, * i /. Możesz również grupować wyrażenia za pomocą nawiasów.
Zauważ, że ta gramatyka jest po prostu bardzo podstawowa: nie obsługuje operatorów jednoargumentowych (minus w: -1 + 9) ani dziesiętnych, takich jak .99 (bez wiodącej liczby), żeby wymienić tylko dwa niedociągnięcia. To tylko przykład, nad którym możesz popracować.
Oto zawartość pliku gramatyki Exp.g :
(Reguły analizatora składni rozpoczynają się od małej litery, a reguły leksykalne zaczynają się od dużej litery)
Po utworzeniu gramatyki będziesz chciał wygenerować z niej parser i leksykon. Pobierz słoik ANTLR i zapisz go w tym samym katalogu, co plik gramatyki.
Wykonaj następujące polecenie w powłoce / wierszu polecenia:
Nie powinien generować żadnego komunikatu o błędzie, a pliki ExpLexer.java , ExpParser.java i Exp.tokens powinny teraz zostać wygenerowane.
Aby sprawdzić, czy wszystko działa poprawnie, utwórz tę klasę testową:
i skompiluj to:
a następnie uruchom:
Jeśli wszystko pójdzie dobrze, nic nie jest drukowane na konsoli. Oznacza to, że parser nie znalazł żadnego błędu. Po zmianie
"12*(5-6)"
na,"12*(5-6"
a następnie ponownej kompilacji i uruchomieniu, należy wydrukować następujące informacje:Okej, teraz chcemy dodać do gramatyki trochę kodu Java, aby parser rzeczywiście zrobił coś pożytecznego. Dodanie kodu można wykonać poprzez umieszczenie w gramatyce
{
i umieszczenie}
w niej zwykłego kodu Java.Ale najpierw: wszystkie reguły parsera w pliku gramatyki powinny zwracać pierwotną podwójną wartość. Możesz to zrobić, dodając
returns [double value]
po każdej regule:co wymaga małego wyjaśnienia: oczekuje się, że każda reguła zwróci podwójną wartość. Teraz, aby „wchodzić w interakcje” z wartością zwracaną
double value
(która NIE znajduje się w zwykłym bloku kodu Java{...}
) z wnętrza bloku kodu, musisz dodać znak dolara przedvalue
:Oto gramatyka, ale teraz z dodanym kodem Java:
a ponieważ nasza
eval
reguła zwraca teraz podwójną wartość, zmień ANTLRDemo.java na:Ponownie (ponownie) wygeneruj nowy leksyk i parser ze swojej gramatyki (1), skompiluj wszystkie klasy (2) i uruchom ANTLRDemo (3):
a teraz zobaczysz wynik wyrażenia
12*(5-6)
wydrukowanego na konsoli!Ponownie: jest to bardzo krótkie wyjaśnienie. Zachęcam do przeglądania wiki ANTLR i przeczytania kilku samouczków i / lub zagrania z tym, co właśnie opublikowałem.
Powodzenia!
EDYTOWAĆ:
Ten post pokazuje, jak rozszerzyć powyższy przykład, aby
Map<String, Double>
można było podać zmienną w podanym wyrażeniu.Aby ten kod działał z aktualną wersją Antlr (czerwiec 2014), musiałem wprowadzić kilka zmian.
ANTLRStringStream
musiał zostaćANTLRInputStream
, zwrócona wartość musiała zmienić się zparser.eval()
naparser.eval().value
, a ja musiałem usunąćWS
klauzulę na końcu, ponieważ takie wartości atrybutów,$channel
które nie mogą już pojawiać się w akcjach leksykalnych.źródło
parser.eval()
zdarzają się implemenacje ? To nie jest jasne TUTAJ lub na ANTLR3 Wiki!eval
to reguła analizatora składni, która zwraca adouble
. Jest więceval()
metoda, którą możesz wywołać na instancjiExpParser
, tak jak pokazałem wANTLRDemo.main(...)
. Po wygenerowaniu lexera / parsera, po prostu otwórz plik,ExpParser.java
a zobaczysz, że istniejeeval()
metoda zwracająca adouble
.Bardzo pomocny jest mega poradnik ANTLR autorstwa Gabriele Tomassetti
Zawiera przykłady gramatyki, przykłady odwiedzających w różnych językach (Java, JavaScript, C # i Python) i wiele innych rzeczy. Wysoce rekomendowane.
EDYCJA: inne przydatne artykuły Gabriele Tomassetti na ANTLR
źródło
W przypadku Antlr 4 proces generowania kodu Java jest poniżej:
Zaktualizuj odpowiednio swoją nazwę słoika w ścieżce klasy.
źródło
Na https://github.com/BITPlan/com.bitplan.antlr znajdziesz bibliotekę Java ANTLR z kilkoma przydatnymi klasami pomocników i kilkoma kompletnymi przykładami. Jest gotowy do użycia z maven, a jeśli lubisz zaćmienie i maven.
https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/exp/Exp.g4
jest prostym językiem wyrażeń, który może wykonywać operacje mnożenia i dodawania. https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestExpParser.java ma dla niego odpowiednie testy jednostkowe.
https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/iri/IRIParser.g4 to parser IRI, który został podzielony na trzy części:
https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIRIParser.java przeprowadza testy jednostkowe.
Osobiście uważam, że jest to najtrudniejsza część, aby rozwiązać problem. Zobacz http://wiki.bitplan.com/index.php/ANTLR_maven_plugin
https://github.com/BITPlan/com.bitplan.antlr/tree/master/src/main/antlr4/com/bitplan/expr
zawiera trzy kolejne przykłady, które zostały utworzone dla problemu z wydajnością ANTLR4 we wcześniejszej wersji. Tymczasem problemy zostały naprawione, jak pokazuje test https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIssue994.java .
źródło
wersja 4.7.1 była nieco inna: do importu:
dla głównego segmentu - zwróć uwagę na CharStreams:
źródło