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ńcucha aab
. Powinieneś dostać dwa dopasowania dla „a”, a następnie błąd (ponieważ b
nie jesta
), ale wtedy spróbuje ponownie z b
powodzeniem.
Można to łatwiej zobaczyć, jeśli wykonasz naprzemiennie z ||
(co wymusza porządek). Jeśli masz
token TOP { I have a <fruit> }
token fruit { apple || orange || kiwi }
i 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ę:
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
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):
grammar test {
rule TOP { <score>+ }
token score {
[
| <uc>
| <lc>
]+
}
token uc { <[A..G]> }
token lc { <[a..g]> }
}
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ć:
grammar test {
rule TOP { <score> + }
token score { <letter> + }
proto token letter { * }
token letter:uc { <[A..G]> }
token letter:lc { <[a..g]> }
}
$<letter>
zawsze będzie zdefiniowane w ten sposób.