В процессе написания переводчика одного музыкального языка на другой (ABC для Alda) в качестве предлога для изучения DSL-способности Raku, я заметил, что, похоже, нет способа прекратить a .parse
! Вот мой сокращенный демонстрационный код:
#!/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;
И это последняя часть дисплея Grammer :: Tracer, которая демонстрирует мою проблему.
| 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
」
Со второй до последней строки слово FAIL говорит мне, что .parse run не имеет возможности выйти. Интересно, правильно ли это? .Say отображает все так, как должно быть, так что я не понимаю, насколько реальна неудача? Остается вопрос: «Как правильно написать грамматику, которая анализирует несколько строк без ошибок?»
Ответы:
Когда вы используете отладчик грамматики, он позволяет вам точно увидеть, как механизм разбирает строку - сбои являются нормальными и ожидаемыми. Рассматривается, например, совпадение
a+b*
со строкойaab
. Вы должны получить два совпадения для «a», после чего произойдет сбой (потому чтоb
это не такa
), но тогда он будет повторенb
и успешно совпадет.Это может быть легче увидеть, если вы чередуетесь с
||
(что обеспечивает порядок). Если у тебя естьи вы анализируете предложение «У меня есть киви», вы увидите, что сначала оно совпадает с «у меня есть», затем два сбоя с «яблоком» и «апельсином», и, наконец, с «киви».
Теперь давайте посмотрим на ваш случай:
Ошибка здесь нормальная: в какой-то момент у нас закончатся
<score>
токены, поэтому ошибка неизбежна. Когда это происходит, механизм грамматики может перейти к тому, что будет после<score>+
вашей грамматики. Поскольку ничего нет, этот сбой на самом деле приводит к совпадению всей строки (потому чтоTOP
совпадает с неявным/^…$/
).Кроме того, вы можете рассмотреть возможность перезаписи вашей грамматики с помощью правила, которое автоматически вставляет <.ws> * (если не важно, чтобы это был только один пробел):
Кроме того, IME, вы можете захотеть добавить протокен для uc / lc, потому что когда он у вас есть,
[ <foo> | <bar> ]
вы всегда будете иметь неопределенный один из них, что может сделать его обработку в классе действий немного раздражающей. Вы можете попробовать:$<letter>
всегда будет определяться таким образом.источник
<.ws>*
автоматически". Подумайте о том, как лучше всего разобраться в том, как лучше не использовать пробелы в грамматике Раку? и Как мне сопоставить шестнадцатеричный массив в грамматике perl6 и Когда пробелы действительно важны в грамматиках раку? ,proto
не слишком сложно, и как только вы освоите его, это сделает вашу жизнь намного проще.