Pourquoi la récursion gauche est-elle mauvaise?

20

Dans la conception du compilateur, pourquoi la récursion gauche devrait-elle être éliminée dans les grammaires? Je lis que c'est parce que cela peut provoquer une récursion infinie, mais n'est-ce pas également vrai pour une grammaire récursive correcte?

Raphael
la source
2
En règle générale, les compilateurs utilisent l'analyse descendante. Si vous avez une récursion gauche, alors l'analyseur va dans une récursion infinie. Cependant, en récursion à droite, l'analyseur peut voir le préfixe de la chaîne qu'il a jusqu'à présent. Ainsi, il peut vérifier si la dérivation est allée "trop ​​loin". Vous pouvez, bien sûr, échanger les rôles et interpréter les expressions de droite, ce qui rend la récursion droite mauvaise et la récursivité gauche très bien.
Shaull
6
La récursivité gauche est mauvaise car dans les temps anciens où les ordinateurs avaient 16 Ko de RAM, le générateur d'analyseur le plus couramment utilisé ne pouvait pas y faire face.
Andrej Bauer

Réponses:

15

Les grammaires récursives gauches ne sont pas nécessairement une mauvaise chose. Ces grammaires sont facilement analysées à l'aide d'une pile pour garder une trace des phrases déjà analysées, comme c'est le cas dans l' analyseur LR .

Rappelons qu'une règle récursive gauche d'une grammaire CF est de la forme:G=(V,Σ,R,S)

ααβ

avec un élément de V et β un élément de V Σ . (Voir la définition formelle complète du tuple ( V , Σ , R , S ) ici ).αVβVΣ(V,Σ,R,S)

βαα

Chaque fois qu'un nouveau terminal est reçu par l'analyseur grammatical (à partir du lexer), ce terminal est poussé au sommet de la pile: cette opération est appelée décalage .

Chaque fois que le côté droit d'une règle correspond à un groupe d'éléments consécutifs en haut de la pile, ce groupe est remplacé par un seul élément représentant la phrase nouvellement mise en correspondance. Ce remplacement s'appelle une réduction .

Avec de bonnes grammaires récursives, la pile peut croître indéfiniment jusqu'à ce qu'une réduction se produise, limitant ainsi de façon assez spectaculaire les possibilités d'analyse. Cependant, ceux récursifs laissés permettront au compilateur de générer des réductions plus tôt (en fait, dès que possible). Voir l' entrée wikipedia pour plus d'informations.

didierc
la source
Il serait utile que vous définissiez vos variables.
Andrew S
12

Considérez cette règle:

example : 'a' | example 'b' ;

Considérons maintenant un analyseur LL essayant de faire correspondre une chaîne qui ne correspond pas 'b'à cette règle. Puisque 'a'ne correspond pas, il essaiera de correspondre example 'b'. Mais pour ce faire, il doit correspondre example... c'est ce qu'il essayait de faire en premier lieu. Il pourrait rester bloqué en essayant pour toujours de voir s'il peut correspondre, car il essaie toujours de faire correspondre le même flux de jetons à la même règle.

Pour éviter cela, vous devez soit analyser à droite (ce qui est assez rare, pour autant que je sache, et faire à la place la bonne récursivité le problème), limiter artificiellement la quantité d'imbrication autorisée, ou correspondre un jeton avant le début de la récursivité donc il y a toujours un cas de base (à savoir, où tous les jetons ont été consommés et il n'y a toujours pas de correspondance complète). Puisqu'une règle récursive droite fait déjà le troisième, elle n'a pas le même problème.

cHao
la source
3
Vous supposez aveuglément que l'analyse est nécessairement une analyse descendante naïve.
reinierpost
Je souligne un piège d'une méthode d'analyse assez courante - un problème qui peut facilement être évité. Il est certainement possible de gérer la récursion à gauche, mais sa conservation crée une limitation presque toujours inutile sur le type d'analyseur qui peut l'utiliser.
cHao
Oui, c'est une façon plus constructive et utile de l'exprimer.
reinierpost
4

(Je sais que cette question est assez ancienne maintenant, mais au cas où d'autres personnes auraient la même question ...)

Demandez-vous dans le contexte des analyseurs de descente récursive? Par exemple, pour la grammaire expr:: = expr + term | term, pourquoi quelque chose comme ça (à gauche récursif):

// expr:: = expr + term
expr() {
   expr();
   if (token == '+') {
      getNextToken();
   }
   term();
}

est problématique, mais pas cela (droit récursif)?

// expr:: = term + expr
expr() {
   term();
   if (token == '+') {
      getNextToken();
      expr();
   }
}

Il ressemble aux deux versions de expr()s'appeler. Mais la différence importante est le contexte - c'est-à-dire le jeton actuel lorsque cet appel récursif est effectué.

Dans le cas récursif gauche, expr()s'appelle continuellement avec le même jeton et aucun progrès n'est fait. Dans le cas récursif de droite, il consomme une partie de l'entrée dans l'appel à term()et le jeton PLUS avant d'atteindre l'appel à expr(). Donc, à ce stade, l'appel récursif peut appeler term, puis se terminer avant d'atteindre à nouveau le test if.

Par exemple, envisagez d'analyser 2 + 3 + 4. L'analyseur récursif gauche appelle expr()infiniment tout en étant bloqué sur le premier jeton, tandis que l'analyseur récursif droit consomme "2 +" avant d'appeler à expr()nouveau. Le deuxième appel expr()correspond à "3 +" et appelle expr()avec seulement le 4 restant. Le 4 correspond à un terme et l'analyse se termine sans plus d'appels à expr().

user65808
la source
2

Du manuel Bison:

"Tout type de séquence peut être défini en utilisant la récursion gauche ou la récursivité droite, mais vous devez toujours utiliser la récursion gauche , car elle peut analyser une séquence de n'importe quel nombre d'éléments avec un espace de pile limité. La récursivité droite utilise de l'espace sur la pile Bison dans proportionnelle au nombre d'éléments dans la séquence, car tous les éléments doivent être déplacés sur la pile avant que la règle ne puisse être appliquée une seule fois. Voir l'algorithme de l'analyseur de bisons, pour plus d'explications. "

http://www.gnu.org/software/bison/manual/html_node/Recursion.html

Cela dépend donc de l'algorithme de l'analyseur, mais comme indiqué dans d'autres réponses, certains analyseurs peuvent tout simplement ne pas fonctionner avec la récursion gauche

Eduardo Wada
la source