2010-08-12 13 views
10

Próbuję napisać parser języka powłoki w Boost.Spirit. Jednak nie mam pewności co do podstawowych problemów dotyczących semantyki rule s.Skopiuj lub odwołaj się do semantyki reguły boost :: spirit <>?

Patrząc na dokumentację, są tam członkowie: r.alias() i r.copy() z rule. IIUC, członkowie ci powinni zwracać odwołanie do reguły i kopii zawartości reguły, odpowiednio. Jednak nie jest jasno określone, co się dzieje, gdy po prostu używam reguły w definicji innej reguły. Z moich doświadczeń, znalazłem wzajemnie rekurencyjne zasady może być zdefiniowana przez:

rule<Iter> r1, r2; 
r1 = ... >> r2 >> ...; 
r2 = ... >> r1 >> ...; 

co sugeruje reguły podejmowane są przez odniesienie wewnątrz wyrażeń parsera. Problemem jest to, co on robi, gdy zmienna wychodzi z zakresu, na przykład:

rule<Iter> r1; 
{ 
    rule<Iter> r2; 
    r1 = ... >> r2 >> ...; 
    r2 = ... >> r1 >> ...; 
} 
... // use r1 

Na tej samej notatki, to przypisanie do przepisu z wyrażeniem analizowania zawierającym rvalue pracy reguła typu (r.copy() byłoby rura typu rule też nie jest? na przykład.

rule<Iter> f() { return char_('a') << char_('b'); } 
rule<Iter> r1 = ... << f(); 

Czy ktoś może mnie oświecić w sprawie szczegółowych semantyki kopii i odniesień rule „s, i ewentualnie skorygować ewentualne nieporozumienia w tym poście?

Odpowiedz

13

Odpowiedź zależy od wersji Ducha, do której się odnosisz.


Spirit.Classic (dawniej Spirit V1.x) implementuje specjalną semantykę kopii dla reguł. Dokumentacja mówi:

Kiedy reguła odnosi nigdzie w prawą stronę wyrażenia EBNF , reguła jest utrzymywany przez wyrażenie przez odniesienie. Obowiązkiem klienta jest , aby zapewnić , że wskazana reguła pozostaje w zasięgu i nie ulega destrukcji , gdy jest przywoływana.

Operator przypisania zasadniczo odwołuje się do reguły rhs bez tworzenia również kopii głębokiej. Zrobiono to, aby umożliwić:

rule<> r1, r2; 
r1 = ...; 
r2 = r1; 

Ale to okazało się bardzo nieporozumieniem, ponieważ uniemożliwiło obsługę reguł w taki sam sposób, jak "normalnych" obiektów.

Z tego powodu istniała funkcja składowa rule::copy(), umożliwiająca tworzenie wyraźnych głębokich kopii reguły (na przykład w celu przechowywania ich w kontenerze STL).

Jednocześnie tym:

r2 = r1.copy(); 

jest bzdura. r2 będzie odnosić się do (zniszczonej) kopii tymczasowej z r1 zwróconej z funkcji copy().


W Spirit.Qi (tj. Spirit V2.x) zachowanie zostało częściowo zmienione.reguły działają teraz zgodnie z oczekiwaniami, gdy są obsługiwane poza parserami. Możesz je normalnie przechowywać w kontenerach (operator przydziału ujawnia oczekiwane zachowanie). Ale uwaga, że ​​wewnątrz parsera zasady ekspresyjne są nadal utrzymywane przez odniesienie, który wystarczy odwołać się do przepisu w taki sam sposób jak poprzednio:

rule<> r1, r2; 
r1 = ... >> r2 >> ...; 
r2 = ... >> r1 >> ...; 

Czasami jest to konieczne, aby głęboką kopię przepisu, więc nie jest nadal członkiem functon copy.

Zmieniona semantyka kopiowania ma inny efekt uboczny. Konstrukty jak:

r1 = r2; 

obecnie stworzenie (głęboki) kopię r2, który nie może być to, czego się spodziewać, zwłaszcza jeśli r2 dostanie swoje prawa oś przydzielone dopiero po „przypisane” do r1. Z tego powodu nie ma nową funkcję członka alias umożliwiające semantyka odniesienia dla tego przypadku narożnego:

r1 = r2.alias(); 

W każdym razie, w obu wersjach Ducha skończy się odniesieniami zwisającymi jeśli część zasad odwoływać od parsera wyrażenie wykracza poza zakres.

BTW, ani wersja Spirit nie implementuje funkcji rule::ref().

+0

Dziękuję za tę odpowiedź. Mam tylko pytanie uzupełniające: Czy jest możliwe używanie wartości rvalues ​​(tymczasowych) wyrażeń parsera jakiegoś typu w wyrażeniu analizatora składni, aby zezwalać na takie instrukcje jak "r1 = r1 | ciąg ("abc") "lub generowanie reguł w funkcji? – jpalecek

+0

Podczas gdy wyrażenie "r1 = r1 | string ("abc") "jest teoretycznie możliwe, że jest lewą rekursją, co spowoduje nieskończoną rekurencję, gdy Spirit generuje parser rekursywny. Ale wyrażenie "r1 = string (" abc ") | r1 "zadziała zgodnie z oczekiwaniami. Możesz wygenerować regułę w funkcji, jeśli upewnisz się, że nie odnosi się ona do żadnej innej reguły, która wykracza poza zakres. Dodatkowo w Spirit.Classic musisz zwrócić r.copy() z funkcji. – hkaiser

+0

'r1 = ciąg ("abc") | r1 'to też lewa rekurencja :) Ale to, co chciałem zrobić, to sprawić, żeby r1 pasowało do r1 dopasowanego wcześniej i "abc". BTW jak mogę wygenerować regułę w funkcji? To nie działa dla mnie: http://pastebin.org/482764 – jpalecek

Powiązane problemy