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ência aab
. Você deve obter duas correspondências para 'a', seguidas por uma falha (porque b
não é a
), mas, em seguida, ele tentará novamente b
e corresponderá com êxito.
Isso pode ser visto com mais facilidade se você alternar com ||
(que impõe ordem). Se você tem
token TOP { I have a <fruit> }
token fruit { apple || orange || kiwi }
e 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:
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
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 (porque TOP
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):
grammar test {
rule TOP { <score>+ }
token score {
[
| <uc>
| <lc>
]+
}
token uc { <[A..G]> }
token lc { <[a..g]> }
}
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:
grammar test {
rule TOP { <score> + }
token score { <letter> + }
proto token letter { * }
token letter:uc { <[A..G]> }
token letter:lc { <[a..g]> }
}
$<letter>
será sempre definido dessa maneira.