En train d'écrire un traducteur d'une langue musicale à une autre (ABC à Alda) comme excuse pour apprendre la capacité Raku DSL, j'ai remarqué qu'il ne semblait pas y avoir de moyen de terminer un .parse
! Voici mon code de démonstration abrégé:
#!/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;
Et c'est la dernière partie de l'affichage Grammer :: Tracer qui illustre mon problème.
| 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
」
Sur l'avant-dernière ligne, le mot FAIL m'indique que le cycle .parse n'a aucun moyen de quitter. Je me demande si c'est correct? Le .say affiche tout comme il se doit, donc je ne sais pas à quel point le FAIL est réel? La question demeure: "Comment écrire correctement une grammaire qui analyse plusieurs lignes sans erreur?"
Réponses:
Lorsque vous utilisez le débogueur de grammaire, il vous permet de voir exactement comment le moteur analyse la chaîne - les échecs sont normaux et attendus. Considéré, par exemple, la correspondance
a+b*
avec la chaîneaab
. Vous devriez obtenir deux correspondances pour 'a', suivies d'un échec (car ceb
n'est pas le casa
), mais il réessayera avecb
et correspondra avec succès.Cela pourrait être plus facile à voir si vous faites une alternance avec
||
(qui applique l'ordre). Si tu aset vous analysez la phrase "J'ai un kiwi", vous le verrez d'abord correspondre "J'ai un", suivi de deux échecs avec "pomme" et "orange", et enfin un match avec "kiwi".
Voyons maintenant votre cas:
L'échec ici est normal: à un moment donné, nous manquerons de
<score>
jetons, donc un échec est inévitable. Lorsque cela se produit, le moteur de grammaire peut passer à tout ce qui vient après<score>+
dans votre grammaire. Puisqu'il n'y a rien, cet échec entraîne en fait une correspondance de la chaîne entière (carTOP
correspond à implicite/^…$/
).En outre, vous pourriez envisager de réécrire votre grammaire avec une règle qui insère <.ws> * automatiquement (sauf s'il est important que ce soit un seul espace):
De plus, IME, vous voudrez peut-être également ajouter un jeton de proto pour l'uc / lc, car lorsque vous en
[ <foo> | <bar> ]
aurez, l'un d'eux sera toujours indéfini, ce qui peut rendre le traitement dans une classe d'actions un peu ennuyeux. Tu pourrais essayer:$<letter>
sera toujours défini de cette façon.la source
<.ws>*
automatique". Pensez à revoir Quelle est la meilleure façon d'être laxiste sur les espaces dans une grammaire Raku? et Comment puis-je faire correspondre un tableau hexadécimal dans la grammaire perl6 et quand l'espace blanc est-il vraiment important dans les grammaires Raku? .proto
n'est pas trop difficile et une fois que vous avez compris, cela vous facilite la vie.