2009-11-02 10 views
6

Usiłuję zbudować gramatyki ANTLR że analizuje oznaczonych zdań takich jak:ANTLR: „brak dostępu atrybut zakresu Rule” problemu

DT The NP cat VB ate DT a NP rat 

i mieć gramatykę:

fragment TOKEN : (('A'..'Z') | ('a'..'z'))+; 
fragment WS : (' ' | '\t')+; 
WSX : WS; 
DTTOK : ('DT' WS TOKEN); 
NPTOK : ('NP' WS TOKEN); 
nounPhrase: (DTTOK WSX NPTOK); 
chunker : nounPhrase {System.out.println("chunk found "+"("+$nounPhrase+")");}; 

Gramatyka generator generuje "missing attribute access on rule scope: nounPhrase" w ostatnim wierszu.

[Wciąż jestem nowy w ANTLR i chociaż niektóre gramatyki działają, wciąż jest to próba i błąd. Często też pojawia się błąd "OutOfMemory", gdy gramarty są tak małe - każda pomoc mile widziane.]

Używam ANTLRWorks 1.3 do generowania kodu i działam w Javie 1.6.

Odpowiedz

1

Odpowiadając na pytanie po znaleźli lepszy sposób ...

WS : (' '|'\t')+; 
TOKEN : (('A'..'Z') | ('a'..'z'))+; 
dttok : 'DT' WS TOKEN; 
nntok : 'NN' WS TOKEN; 
nounPhrase : (dttok WS nntok); 
chunker : nounPhrase ; 

Problem polegał na tym, że wychodzę pomieszania między lexer i parsera (to podobno bardzo często). Wielkie elementy są leksykalne, małe w parserze. Teraz wydaje się, że działa. (NB: Zmieniłem NP na NN).

2

W oryginalnym Grammer, dlaczego nie zawierają atrybut to prosi, najprawdopodobniej:

chunker : nounPhrase {System.out.println("chunk found "+"("+$nounPhrase.text+")");}; 

Każda z reguł (chunker będąc jednym mogę dostrzec szybko) mają atrybuty (dodatkowe informacje) związane z nimi. Możesz znaleźć szybką listę różnych atrybutów dla różnych typów reguł na http://www.antlr.org/wiki/display/ANTLR3/Attribute+and+Dynamic+Scopes, byłoby miło, gdyby opisy zostały umieszczone na stronie dla każdego z tych atrybutów (podobnie jak dla atrybutu start i stop reguł parsera odnoszą się do tokenów od twojego lexera - co pozwoliłoby ci wrócić do numeru linii i pozycji).

Myślę, że twoja reguła powinna być nieco zmieniona, zamiast $nounPhrase powinieneś użyć $nounPhrase.text. text to atrybut twojej reguły nounPhrase.

Czasami warto zrobić trochę inne formatowanie, a także, zwykle zasady parsera (start z małej litery) stawienia się przed zasadami Lexer (start z wielkiej litery)

PS. Kiedy piszę w polu, reguła chunker zaczyna się na nowej linii, ale w mojej oryginalnej odpowiedzi nie zaczęła się w nowej linii.

+0

Czy mógłbyś wyjaśnić dalej, proszę? Nie jestem pewien, co to jest atrybut –

8

„brak dostępu atrybut” oznacza, że ​​już odwoływać do zakresu ($nounPhrase) zamiast atrybut zakresie (takich jak $nounPhrase.text) .

Ogólnie rzecz biorąc, dobrym sposobem rozwiązywania problemów z atrybutami jest analiza wygenerowanej metody analizowania składni dla danej reguły.

Na przykład, moja pierwsza próba stworzenia nowej reguły, kiedy byłem trochę zardzewiały:

multiple_names returns [List<Name> names] 
@init { 
    names = new ArrayList<Name>(4); 
} 
: a=fullname ' AND ' b=fullname { names.add($a.value); names.add($b.value); }; 

spowodowało „nieznanego atrybutu dla reguły FULLNAME”.Dlatego starałem

multiple_names returns [List<Name> names] 
@init { 
    names = new ArrayList<Name>(4); 
} 
: a=fullname ' AND ' b=fullname { names.add($a); names.add($b); }; 

co skutkuje "brakuje dostępu atrybutu". Patrząc na wygenerowaną metodę analizatora składni, wyjaśniono, co muszę zrobić. Chociaż istnieją pewne tajemnicze fragmenty, części dotyczące zakresem produktów (zmiennych) są łatwo zrozumiałe:

public final List<Name> multiple_names() throws RecognitionException { 
    List<Name> names = null;  // based on "returns" clause of rule definition 
    Name a = null;     // based on scopes declared in rule definition 
    Name b = null;     // based on scopes declared in rule definition 
    names = new ArrayList<Name>(4); // snippet inserted from `@init` block 

    try { 
     pushFollow(FOLLOW_fullname_in_multiple_names42); 
     a=fullname(); 
     state._fsp--; 
     match(input,189,FOLLOW_189_in_multiple_names44); 
     pushFollow(FOLLOW_fullname_in_multiple_names48); 
     b=fullname(); 
     state._fsp--; 
     names.add($a); names.add($b);// code inserted from {...} block 
    } 
    catch (RecognitionException re) { 
     reportError(re); 
     recover(input,re); 
    } 
    finally { 
     // do for sure before leaving 
    } 
    return names;     // based on "returns" clause of rule definition 
} 

Po zapoznaniu się z wygenerowanego kodu, to łatwo zauważyć, że zasada fullname wraca instancje klasy Name, więc co potrzebne w tym przypadku po prostu:

multiple_names returns [List<Name> names] 
@init { 
    names = new ArrayList<Name>(4); 
} 
: a=fullname ' AND ' b=fullname { names.add(a); names.add(b); }; 

wersja trzeba w danej sytuacji mogą być różne, ale generalnie będziesz w stanie zrozumieć to dość łatwo, patrząc na wygenerowanego kodu.

1

Jeśli przypadkowo zrobisz coś głupiego, jak $thing.$attribute, jeśli masz na myśli $thing.attribute, zobaczysz również komunikat o błędzie missing attribute access on rule scope. (Wiem, że odpowiedź na to pytanie była dawno temu, ale ta odrobina ciekawostek może pomóc komuś innemu, kto zobaczy komunikat o błędzie!)