W trakcie pisania tłumacza jednego języka muzycznego na inny (od ABC do Alda) jako wymówki do nauki umiejętności Raku DSL zauważyłem, że nie ma sposobu na zakończenie .parse
! Oto mój skrócony kod demonstracyjny:
#!/home/hsmyers/rakudo741/bin/perl6
use v6d;
# use Grammar::Debugger;
use Grammar::Tracer;
my $test-n01 = q:to/EOS/;
a b c d e f g
A B C D E F G
EOS
grammar test {
token TOP { <score>+ }
token score {
<.ws>?
[
| <uc>
| <lc>
]+
<.ws>?
}
token uc { <[A..G]> }
token lc { <[a..g]> }
}
test.parse($test-n01).say;
I to ostatnia część wyświetlacza Grammer :: Tracer pokazuje mój problem.
| score
| | uc
| | * MATCH "G"
| * MATCH "G\n"
| score
| * FAIL
* MATCH "a b c d e f g\nA B C D E F G\n"
「a b c d e f g
A B C D E F G
」
W wierszu od drugiego do ostatniego słowo FAIL mówi mi, że uruchomienie .parse nie ma możliwości wyjścia. Zastanawiam się, czy to jest poprawne? .Say wyświetla wszystko tak, jak powinno być, więc nie jestem pewien, jak prawdziwy jest FAIL? Pozostaje pytanie: „Jak poprawnie napisać gramatykę, która analizuje wiele wierszy bez błędów?”
Odpowiedzi:
Kiedy używasz debugera gramatyki, pozwala dokładnie zobaczyć, w jaki sposób silnik analizuje ciąg - awarie są normalne i oczekiwane. Uważane na przykład za pasujące
a+b*
do łańcuchaaab
. Powinieneś dostać dwa dopasowania dla „a”, a następnie błąd (ponieważb
nie jesta
), ale wtedy spróbuje ponownie zb
powodzeniem.Można to łatwiej zobaczyć, jeśli wykonasz naprzemiennie z
||
(co wymusza porządek). Jeśli maszi parsujesz zdanie „Mam kiwi”, zobaczysz, że najpierw pasuje do „Mam”, potem dwa kończą się niepowodzeniem z „jabłkiem” i „pomarańczą”, a na końcu pasują do „kiwi”.
Teraz spójrzmy na twoją skrzynkę:
Błąd tutaj jest normalny: w pewnym momencie zabraknie
<score>
tokenów, więc błąd jest nieunikniony. Kiedy tak się dzieje, silnik gramatyki może przejść do wszystkiego, co nastąpi po<score>+
gramatyce. Ponieważ nie ma nic, to niepowodzenie powoduje dopasowanie całego łańcucha (ponieważTOP
pasuje do niejawnego/^…$/
).Możesz również rozważyć przepisanie gramatyki z regułą, która wstawia <.ws> * automatycznie (chyba że ważne jest, aby była to pojedyncza spacja):
Ponadto, IME, możesz chcieć również dodać token proto dla uc / lc, ponieważ kiedy będziesz
[ <foo> | <bar> ]
, zawsze będziesz mieć jeden z nich niezdefiniowany, co może sprawić, że przetwarzanie ich w klasie działań będzie trochę denerwujące. Możesz spróbować:$<letter>
zawsze będzie zdefiniowane w ten sposób.źródło
<.ws>*
automatycznego”. Zastanów się nad recenzją Jaki jest najlepszy sposób na rozluźnienie białych znaków w gramatyce Raku? oraz W jaki sposób dopasować układ heksadecymalny w gramatyce perl6 i Kiedy biała przestrzeń jest naprawdę ważna w gramatyce Raku? .proto
nie jest zbyt trudne, a kiedy już to zrozumiesz, znacznie ułatwi ci życie.