2013-08-28 10 views
18

Tydzień temu rozpocząłem następujący projekt: gramatykę, która rozpoznaje przyrostki kodu Java.ANTLR: Jak można wyjaśnić zachowanie tej gramatyki, która rozpoznaje przyrostki kodu Java?

Użyłem oficjalnej gramatyki ANTLR dla Java (Java.g4) jako linii bazowej i zacząłem dodawać reguły. Jednak te nowe zasady wprowadziły również lewą rekursję, z którą również musiałem się uporać.

Po kilku dniach pracy miałem following code. Kiedy zacząłem testowanie zauważyłem coś niezwykłego, czego wciąż nie potrafię wytłumaczyć. Po wprowadzeniu danych wejściowych { } parser mówi mi: no viable alternative at input '<EOF>', ale kiedy przełączam kolejność terminali z praworęcznej strony reguły s2, szczególnie jeśli zmienimy praworęczną stronę z v2_1 | v2_2 | v2_3 ... na v2_36 | v2_1 | v2_2 ... (terminal v2_36 zostanie przeniesiony na pierwsza pozycja), sekwencja { } zostaje zaakceptowana.

Moje pierwsze myśli były że Antlr nie wracać, bo zauważył, że z wejściem { } pierwsza wersja parsera zacznie przestrzegać zasady v2_3 i po prostu informuje, że nic się nie znalazł i nie starają się rozważyć inne opcje (to co myślę, ale może to nie jest prawda) jak v2_36, które dają dokładnie pozytywną odpowiedź.

Po kilku badaniach dowiedziałem się, że ANTLR faktycznie cofa się, ale tylko wtedy, gdy wszystko inne zawiedzie. Przynajmniej tak jest w v3.3 (przeczytaj w oficjalnym dokumencie ANTLR), ale domyślam się, że jest to również prawdziwe dla v4. Teraz jestem nieco zdezorientowany. Po spędzeniu tylu godzin na tym projekcie czułbym się okropnie, gdybym nie sprawił, żeby to działało. Czy ktoś może dać jakąś wskazówkę lub coś takiego? Byłoby to bardzo docenione, dzięki.

EDIT

Udało się wyizolować problem do

grammar Java; 
@parser::members {String ruleName; } 

start : compilationUnitSuf EOF; 

compilationUnitSuf 
    : {ruleName = "typeDeclarationSuf"; } s2 
    ; 

s2: '{' '}' v2_81 | '{' '}'; 
v2_81 : {ruleName.equals("enumBodyDeclarationsSuf")}? t173 | t173 '}'; 
t173: '}' | '{'*; 

LBRACKET: '{'; 
RBRACKET: '}'; 

WS : [ \t\r\n\u000C]+ -> skip 
    ; 

Dlaczego więc algorytm przewidywanie zasugerować mi podążać s2 -> v'{' '}' v2_81 -> ... zamiast s2 -> '{' '}'?

+1

Nie mam pojęcia, co masz na myśli przez _ "przyrostki kodu Java" _. –

+0

Jeśli mamy sekwencję 'a [1..n]' tokenów danego kodu Java, definiujemy sufiks jako sekwencję 'a [j], a [j + 1], ..., a [ n] 'dla niektórych' 1 <= j <= n' (dla kodu 'klasa A {int a;}' możliwe sufiksy to 'A {int a;}', '{int a;}', 'int a ;} 'itp.), ale myślę, że to nie ma znaczenia dla pytania – svs

+2

Czy istnieje powód, dla którego używasz ANTLR? W przypadku parsowania sufiksów parser GLR byłby o wiele łatwiejszy i zaimplantuje analizę gramatyki LR (1) w przybliżonym czasie liniowym, iirc. W Grune & Jacobs (Parsing Techniques: A Practical Guide) jest cały rozdział o analizie sufiksów. – rici

Odpowiedz

1

Uważam, że przekonasz się, że nie jest to powrót w oczekiwany sposób. Powodem jest, że znajduje {}, a następnie spodziewa się zobaczyć v2_181, którego nie znajdzie. ponieważ nie cofa się, nie znajduje alternatywy, którą chcesz. Alternatywą jest po prostu opcjonalne dodanie opcji v2_181, dlatego nie jest konieczne cofanie. Coś jak poniżej:

grammar Java; 
@parser::members {String ruleName; } 

start : compilationUnitSuf EOF; 

compilationUnitSuf 
    : {ruleName = "typeDeclarationSuf"; } s2 
    ; 

s2: '{' '}' v2_81?; 
v2_81 : {ruleName.equals("enumBodyDeclarationsSuf")}? t173 | t173 '}'; 
t173: '}' | '{'*; 

LBRACKET: '{'; 
RBRACKET: '}'; 

WS : [ \t\r\n\u000C]+ -> skip 
    ; 
Powiązane problemy