No processo de escrever um tradutor de uma linguagem musical para outra (ABC para Alda) como uma desculpa para aprender a capacidade DSL do Raku, notei que não parece haver uma maneira de encerrar a .parse
! Aqui está o meu código de demonstração abreviado:
#!/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;
E é a última parte da tela Grammer :: Tracer que demonstra meu problema.
| 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
」
Na penúltima linha, a palavra FAIL diz que a execução .parse não tem como sair. Gostaria de saber se isso está correto? O .say mostra tudo como deve ser, então não tenho certeza de quão real é o FAIL? A pergunta permanece: "Como escrevo corretamente uma gramática que analisa várias linhas sem erro?"
Respostas:
Quando você usa o depurador de gramática, ele permite que você veja exatamente como o mecanismo está analisando a sequência - as falhas são normais e esperadas. Considerado, por exemplo, correspondência
a+b*
com a sequênciaaab
. Você deve obter duas correspondências para 'a', seguidas por uma falha (porqueb
não éa
), mas, em seguida, ele tentará novamenteb
e corresponderá com êxito.Isso pode ser visto com mais facilidade se você alternar com
||
(que impõe ordem). Se você teme você analisa a frase "eu tenho um kiwi", você verá a primeira correspondência "eu tenho um", seguida de duas falhas com "maçã" e "laranja" e, finalmente, uma correspondência com "kiwi".
Agora vamos ver o seu caso:
A falha aqui é normal: em algum momento, ficaremos sem
<score>
fichas, portanto, uma falha é inevitável. Quando isso acontece, o mecanismo de gramática pode passar para o que vier depois da<score>+
gramática. Como não há nada, essa falha realmente resulta em uma correspondência de toda a cadeia de caracteres (porqueTOP
corresponde ao implícito/^…$/
).Além disso, você pode reescrever sua gramática com uma regra que insere <.ws> * automaticamente (a menos que seja importante que seja apenas um espaço):
Além disso, IME, você também pode querer adicionar um token proto para o uc / lc, porque quando o tiver
[ <foo> | <bar> ]
, sempre haverá um deles indefinido, o que pode tornar um pouco irritante o processamento deles em uma classe de ações. Você poderia tentar:$<letter>
será sempre definido dessa maneira.fonte
<.ws>*
automaticamente". Considere revisar Qual é a melhor maneira de ser indiferente aos espaços em branco na gramática Raku? e Como eu combino uma matriz hexadecimal na gramática perl6 e Quando o espaço em branco é realmente importante nas gramáticas Raku? .proto
não é muito difícil e, quando você pega o jeito, torna sua vida muito mais fácil.