Когда вы используете отладчик грамматики, он позволяет вам точно увидеть, как механизм разбирает строку - сбои являются нормальными и ожидаемыми. Рассматривается, например, совпадение a+b*со строкой aab. Вы должны получить два совпадения для «a», после чего произойдет сбой (потому что bэто не так a), но тогда он будет повторен bи успешно совпадет.
Это может быть легче увидеть, если вы чередуетесь с ||(что обеспечивает порядок). Если у тебя есть
token TOP { I have a <fruit> }
token fruit { apple || orange || kiwi }
и вы анализируете предложение «У меня есть киви», вы увидите, что сначала оно совпадает с «у меня есть», затем два сбоя с «яблоком» и «апельсином», и, наконец, с «киви».
Теперь давайте посмотрим на ваш случай:
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
Ошибка здесь нормальная: в какой-то момент у нас закончатся <score>токены, поэтому ошибка неизбежна. Когда это происходит, механизм грамматики может перейти к тому, что будет после <score>+вашей грамматики. Поскольку ничего нет, этот сбой на самом деле приводит к совпадению всей строки (потому что TOPсовпадает с неявным /^…$/).
Кроме того, вы можете рассмотреть возможность перезаписи вашей грамматики с помощью правила, которое автоматически вставляет <.ws> * (если не важно, чтобы это был только один пробел):
grammar test {
rule TOP { <score>+ }
token score {
[
| <uc>
| <lc>
]+
}
token uc { <[A..G]> }
token lc { <[a..g]> }
}
Кроме того, IME, вы можете захотеть добавить протокен для uc / lc, потому что когда он у вас есть, [ <foo> | <bar> ]вы всегда будете иметь неопределенный один из них, что может сделать его обработку в классе действий немного раздражающей. Вы можете попробовать:
grammar test {
rule TOP { <score> + }
token score { <letter> + }
proto token letter { * }
token letter:uc { <[A..G]> }
token letter:lc { <[a..g]> }
}
$<letter> всегда будет определяться таким образом.