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 -> '{' '}'
?
Nie mam pojęcia, co masz na myśli przez _ "przyrostki kodu Java" _. –
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
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