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îne aab
. Vous devriez obtenir deux correspondances pour 'a', suivies d'un échec (car ce b
n'est pas le cas a
), mais il réessayera avec b
et correspondra avec succès.
Cela pourrait être plus facile à voir si vous faites une alternance avec ||
(qui applique l'ordre). Si tu as
token TOP { I have a <fruit> }
token fruit { apple || orange || kiwi }
et 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:
TOP # Trying to match top (need >1 match of score)
| score # Trying to match score (need >1 match of lc/uc)
| | lc # Trying to match lc
| | * MATCH "a" # lc had a successful match! ("a")
| * MATCH "a " # and as a result so did score! ("a ")
| score # Trying to match score again (because <score>+)
| | lc # Trying to match lc
| | * MATCH "b" # lc had a successful match! ("b")
| * MATCH "b " # and as a result so did score! ("b ")
…………… # …so forth and so on until…
| score # Trying to match score again (because <score>+)
| | uc # Trying to match uc
| | * MATCH "G" # uc had a successful match! ("G")
| * MATCH "G\n" # and as a result, so did score! ("G\n")
| score # Trying to match *score* again (because <score>+)
| * FAIL # failed to match score, because no lc/uc.
|
| # <-------------- At this point, the question is, did TOP match?
| # Remember, TOP is <score>+, so we match TOP if there
| # was at least one <score> token that matched, there was so...
|
* MATCH "a b c d e f g\nA B C D E F G\n" # this is the TOP match
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 (car TOP
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):
grammar test {
rule TOP { <score>+ }
token score {
[
| <uc>
| <lc>
]+
}
token uc { <[A..G]> }
token lc { <[a..g]> }
}
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:
grammar test {
rule TOP { <score> + }
token score { <letter> + }
proto token letter { * }
token letter:uc { <[A..G]> }
token letter:lc { <[a..g]> }
}
$<letter>
sera toujours défini de cette façon.