Les conflits vous montrent indiquer un problème avec la façon dont le non-terminal number
est il utilisé, pas avec number
lui-même.
Le problème de base est que, après avoir vu un pnumber
ou nnumber
, lorsque le prochain jeton de test avant est un DOT
, il ne peut pas décider si cela devrait être la fin de la number
(réduire, si DOT
fait partie d'un autre non terminal après du number
), ou si le DOT
doit être traité dans le cadre du number
(déplacé de sorte qu'il peut ensuite réduire l'un des p/nNombre règles DOT de pNuméro.)
Ainsi, afin de diagnostiquer la problème, vous devrez montrer toutes les règles qui utilisent number
n'importe où sur le côté droit (et se répète toutes les autres règles qui utilisent les non-terminaux de ces règles sur la droite).
Notez qu'il est rarement utile pour poster juste un fragment d'une grammaire, comme le processus de construction de l'analyseur LR dépend fortement du contexte où les règles sont utilisées ailleurs dans la grammaire ...
Donc, le problème ici est que vous avez besoin de lookahead à deux jetons pour faire la différence entre un DOT
dans un (réel) literal
et un DOT
à la fin d'un rule
.
La solution facile est de laisser l'affaire lexer avec elle - lexers peuvent faire de petites quantités de préanalyse assez facilement, de sorte que vous pouvez reconnaître REAL_NUMBER
comme un non-terminal distinct de NUMBER
(probablement encore sans -
, de sorte que vous » d finir avec
number ::= NUMBER | MINUS NUMBER | REAL_NUMBER | MINUS REAL_NUMBER
est beaucoup plus difficile à éliminer le conflit par affacturage la grammaire, mais il peut être fait.
en général, pour factoriser une grammaire pour supprimer un conflit d'anticipation, vous devez trouver les règles qui manifestent le conflit (rule
et number
ici) et refactoriser les choses pour les rassembler dans des règles qui ont des préfixes communs jusqu'à ce que vous soyez assez loin pour désambiguïser. Tout d'abord, je vais supposer qu'il existe d'autres règles que number
qui peuvent apparaître ici, sinon nous pourrions simplement éliminer toutes les règles intermédiaires.
variable ::= number | name
Nous voulons déplacer la règle number
« up » dans la grammaire pour l'obtenir dans le même endroit que rule
avec DOT
. Nous avons donc besoin de diviser les règles contenant à un cas particulier quand ils se terminent par un number
. Nous ajoutons un suffixe pour désigner les règles qui correspondent à la règle d'origine avec toutes les versions qui se terminent par un number
séparé
variable ::= number | variable_n
variable_n ::= name
... et ProGate que « up »
literal ::= number | literal_n
literal_n ::= variable_n
... et agin
bodydef ::= number | bodydef_n
bodydef_n := literal_n
... et encore
body ::= number | body_n
body := body CONUNCTION number
body_n ::= bodydef_n
body_n ::= body CONJUNCTION bodydef_n
Notez que lorsque vous le déplacez vers le haut, vous devez diviser de plus en plus de règles, ce processus peut donc faire exploser la grammaire. Cependant, les règles qui sont utilisées seulement à la fin d'un rhs que vous refactoring finira par avoir seulement besoin de la version _n
, donc vous n'avez pas nécessairement à doubler le nombre de règles.
... dernière étape
rule ::= REVERSE_IMPLICATION body_n DOT
rule ::= REVERSE_IMPLICATION number DOT
rule ::= REVERSE_IMPLICATION body CONJUNCTION number DOT
Vous avez maintenant les points dans les mêmes endroits, donc élargir les règles number
:
rule ::= REVERSE_IMPLICATION body_n DOT
rule ::= REVERSE_IMPLICATION integer DOT
rule ::= REVERSE_IMPLICATION integer DOT pnumber DOT
rule ::= REVERSE_IMPLICATION body CONJUNCTION integer DOT
rule ::= REVERSE_IMPLICATION body CONJUNCTION integer DOT pnumber DOT
et les conflits décalage réduire ces risques sont partis, parce que les règles ont des préfixes communs jusqu'à la fin de l'anticipation nécessaire pour déterminer lequel utiliser. J'ai réduit le nombre de règles dans cette expansion finale en ajoutant
integer ::= pnumber | nnumber
Veuillez créer un MCVE ([MCVE]) pour cela. Avec les étiquettes '(N)' enlevées (elles ne sont pas utilisées), le fragment donné ne produit pas un décalage réduit le conflit avec le citron de SQLite 3.14.0. Au minimum, vous devriez regarder dans le fichier '.out' et inclure les informations de conflit pertinentes dans la question, mais il serait préférable de produire un fragment de grammaire qui peut être copié et qui reproduit le problème. Ensuite, nous pouvons vous aider (probablement). Jusque-là, nous sommes coincés. –
@JonathanLeffler J'ai ajouté la sortie du fichier .out où les conflits se produisent. Les étiquettes (N) sont effectivement utilisées mais je les ai retirées de la question par souci de concision. –
Bien sûr, les étiquettes sont utilisées dans votre vraie grammaire - mais elles sont gênantes lorsque vous essayez de vous aider. Vous devez travailler sur la MCVE-ization de votre code. Les changements à 39 et 40 sont pertinents - mais nous ne savons pas à quelles règles ils font partie. Le problème peut être que votre grammaire doit regarder deux jetons - qu'est-ce qu'il obtient après le DOT. Si tel est le problème, vous avez probablement besoin d'améliorer votre analyseur lexical afin que, plutôt que la grammaire, il gère les nombres décimaux par rapport aux entiers, en retournant différents jetons (par exemple NUMBER comme maintenant et DECIMAL). Notez que les zéros en tête sont significatifs après DOT. –