web-dev-qa-db-fra.com

Quelle est la différence entre l'analyse LR (0) et SLR?

Je travaille sur mes concepts de compilateurs mais je suis un peu confus ... La recherche sur Google ne m'a permis d'obtenir aucune réponse définitive.

Les analyseurs SLR et LR (0) sont-ils identiques? Sinon, quelle est la différence?

71
Nitish Upreti

Les analyseurs LR (0) et SLR (1) sont tous deux analyseurs ascendants, directionnels et prédictifs. Cela signifie que

  • Les analyseurs tentent d'appliquer les productions à l'envers pour réduire la phrase d'entrée au symbole de début ( de bas en haut)
  • Les analyseurs analysent l'entrée de gauche à droite ( directionnel)
  • Les analyseurs tentent de prédire quelles réductions appliquer sans nécessairement voir toutes les entrées ( prédictif)

LR (0) et SLR (1) sont tous deux analyseurs de décalage/réduction , ce qui signifie qu'ils traitent les jetons du flux d'entrée en les plaçant sur une pile , et à chaque point soit déplacer un jeton en le poussant sur la pile ou réduire une séquence de terminaux et de terminaux non placés au sommet de la pile vers un symbole non terminal. On peut montrer que n'importe quelle grammaire peut être analysée de bas en haut en utilisant un analyseur de décalage/réduction, mais cet analyseur peut ne pas être déterministe. Autrement dit, l'analyseur peut avoir à "deviner" s'il faut appliquer un décalage ou une réduction, et peut finir par avoir à revenir en arrière pour se rendre compte qu'il a fait le mauvais choix. Quelle que soit la puissance d'un analyseur de changement/réduction déterministe que vous construisez, il ne pourra jamais analyser toutes les grammaires.

Lorsqu'un analyseur déterministe de décalage/réduction est utilisé pour analyser une grammaire qu'il ne peut pas gérer, il en résulte des conflits de décalage/réduction ou réduire/réduire les conflits , où l'analyseur peut entrer dans un état dans lequel il ne peut pas dire quelle action entreprendre. Dans un conflit de décalage/réduction, il ne peut pas dire s'il doit ajouter un autre symbole à la pile ou effectuer une certaine réduction sur les symboles supérieurs de la pile. Dans un conflit réduire/réduire, l'analyseur sait qu'il doit remplacer les symboles supérieurs de la pile par des éléments non terminaux, mais il ne peut pas dire quelle réduction utiliser.

Je m'excuse s'il s'agit d'une longue exposition, mais nous en avons besoin pour pouvoir faire la différence entre l'analyse LR (0) et SLR (1). Un analyseur LR (0) est un analyseur de décalage/réduction qui utilise zéro jeton d'anticipation pour déterminer l'action à entreprendre (d'où le 0). Cela signifie que dans n'importe quelle configuration de l'analyseur, l'analyseur doit avoir une action non ambiguë à choisir - soit il décale un symbole spécifique, soit applique une réduction spécifique. S'il y a deux ou plusieurs choix à faire, l'analyseur échoue et nous disons que la grammaire n'est pas LR (0).

Rappelons que les deux conflits LR possibles sont shift/réduire et réduire/réduire. Dans ces deux cas, il y a au moins deux actions que l'automate LR (0) pourrait entreprendre, et il ne peut pas dire lesquelles utiliser. Puisqu'au moins une des actions en conflit est une réduction, une ligne d'attaque raisonnable serait d'essayer de faire en sorte que l'analyseur soit plus prudent lorsqu'il effectue une réduction particulière. Plus précisément, supposons que l'analyseur est autorisé à regarder le prochain jeton d'entrée pour déterminer s'il doit se déplacer ou se réduire. Si nous permettons uniquement à l'analyseur de réduire lorsqu'il "fait sens" de le faire (pour une définition de "fait sens"), alors nous pourrons peut-être éliminer le conflit en faisant en sorte que l'automate choisisse spécifiquement de déplacer ou de réduire dans un étape particulière.

Dans SLR (1) ("LR simplifié (1)"), l'analyseur est autorisé à regarder un jeton d'anticipation lorsqu'il décide s'il doit se déplacer ou se réduire. En particulier, lorsque l'analyseur veut essayer de réduire quelque chose de la forme A → w (pour le non terminal A et la chaîne w), il regarde le prochain jeton d'entrée. Si ce jeton pouvait légalement apparaître après le non terminal A dans une certaine dérivation, l'analyseur réduit. Sinon, ce n'est pas le cas. L'intuition ici est que, dans certains cas, cela n'a aucun sens de tenter une réduction, car étant donné les jetons que nous avons vus jusqu'à présent et le jeton à venir, il n'y a aucun moyen possible que la réduction soit jamais correcte.

La seule différence entre LR (0) et SLR (1) est cette capacité supplémentaire d'aider à décider des mesures à prendre en cas de conflit. Pour cette raison, toute grammaire qui peut être analysée par un analyseur LR (0) peut être analysée par un analyseur SLR (1). Cependant, les analyseurs SLR (1) peuvent analyser un plus grand nombre de grammaires que LR (0).

En pratique, cependant, SLR (1) est encore une méthode d'analyse assez faible. Plus communément, vous verrez des analyseurs LALR (1) ("Lookahead LR (1)") utilisés. Ils travaillent également en essayant de résoudre les conflits dans un analyseur LR (0), mais les règles qu'ils utilisent pour résoudre les conflits sont beaucoup plus précises que celles utilisées dans SLR (1), et par conséquent un nombre beaucoup plus grand de grammaires sont LALR (1) que SLR (1). Pour être un peu plus précis, les analyseurs SLR (1) essaient de résoudre les conflits en examinant la structure de la grammaire pour en savoir plus sur le moment du décalage et le moment de la réduction. Les analyseurs LALR (1) examinent à la fois la grammaire et l'analyseur LR (0) pour obtenir des informations encore plus précises sur le moment du décalage et le moment de la réduction. Parce que LALR (1) peut regarder la structure de l'analyseur LR (0), il peut identifier plus précisément quand certains conflits sont faux. Les utilitaires Linux yacc et bison, par défaut, produisent des analyseurs LALR (1).

Historiquement, les analyseurs LALR (1) étaient généralement construits par une méthode différente qui s'appuyait sur l'analyseur LR (1) beaucoup plus puissant, vous verrez donc souvent LALR (1) décrit de cette façon. Pour comprendre cela, nous devons parler des analyseurs LR (1). Dans un analyseur LR (0), l'analyseur fonctionne en gardant une trace de l'endroit où il pourrait se trouver au milieu d'une production. Une fois qu'il a constaté qu'il a atteint la fin d'une production, il sait essayer de réduire. Cependant, l'analyseur pourrait ne pas être en mesure de dire s'il se trouve à la fin d'une production et au milieu d'une autre, ce qui entraîne un changement/réduire le conflit, ou de laquelle des deux productions différentes il a atteint la fin (une réduction/réduire les conflits). Dans LR (0), cela conduit immédiatement à un conflit et l'analyseur échoue. Dans SLR (1) ou LALR (1), l'analyseur prend alors la décision de décaler ou de réduire en fonction du prochain jeton d'anticipation.

Dans un analyseur LR (1), l'analyseur conserve une trace des informations supplémentaires pendant son fonctionnement. En plus de garder une trace de la production qui, selon l'analyseur, est utilisée, il garde une trace des jetons qui pourraient apparaître une fois la production terminée. Parce que l'analyseur garde une trace de ces informations à chaque étape, et pas seulement au moment de prendre la décision, l'analyseur LR (1) est sensiblement plus puissant et précis que n'importe lequel des LR (0), SLR (1) ou Analyseurs LALR (1) dont nous avons parlé jusqu'à présent. LR (1) est une technique d'analyse extrêmement puissante, et il peut être montré en utilisant des mathématiques délicates que tout langage qui pourrait être analysé de manière déterministe par n'importe quel shift/réduire l'analyseur a une grammaire qui pourrait être analysée avec un automate LR (1). (Notez que cela ne signifie pas que toutes les grammaires qui peuvent être analysées de manière déterministe sont LR (1); cela indique seulement qu'un langage qui pourrait être analysé de façon déterministe a une grammaire LR (1)). Cependant, cette puissance a un prix, et un analyseur LR (1) généré peut nécessiter tellement d'informations pour fonctionner qu'il ne peut pas être utilisé dans la pratique. Un analyseur LR (1) pour un vrai langage de programmation, par exemple, peut nécessiter des dizaines à des centaines de mégaoctets d'informations supplémentaires pour fonctionner correctement. Pour cette raison, LR (1) n'est généralement pas utilisé dans la pratique, et des analyseurs plus faibles comme LALR (1) ou SLR (1) sont utilisés à la place.

Plus récemment, un nouvel algorithme d'analyse appelé GLR (0) ("Generalized LR (0)") a gagné en popularité. Plutôt que d'essayer de résoudre les conflits qui apparaissent dans un analyseur LR (0), l'analyseur GLR (0) fonctionne à la place en essayant toutes les options possibles en parallèle. En utilisant quelques astuces intelligentes, cela peut être fait pour fonctionner très efficacement pour de nombreuses grammaires. De plus, GLR (0) peut analyser n'importe quelle grammaire sans contexte, même les grammaires qui ne peuvent pas être analysées par un analyseur LR (k) pour n'importe quel k. D'autres analyseurs sont également capables de le faire (par exemple, l'analyseur Earley ou un analyseur CYK), bien que GLR (0) ait tendance à être plus rapide dans la pratique.

Si vous souhaitez en savoir plus, cet été, j'ai enseigné un cours d'introduction aux compilateurs et passé un peu moins de deux semaines à parler des techniques d'analyse. Si vous souhaitez obtenir une introduction plus rigoureuse à LR (0), SLR (1) et à de nombreuses autres techniques d'analyse puissantes, vous pourriez apprécier mes diapositives de cours et mes devoirs sur l'analyse. Tous les supports de cours sont disponibles ici sur mon site personnel .

J'espère que cela t'aides!

224
templatetypedef

Voilà ce que j'ai appris. Généralement, l'analyseur LR (0) peut avoir une ambiguïté, c'est-à-dire qu'une case de la table (que vous dérivez pour créer l'analyseur) peut avoir plusieurs valeurs (ou) pour mieux le dire: l'analyseur mène à deux états finaux avec la même entrée. L'analyseur SLR est donc créé pour lever cette ambiguïté. Afin de le construire, recherchez toutes les productions qui mènent à des états goto, recherchez la suite pour le symbole de production sur le côté gauche et n'incluez que les goto états qui sont présents dans la suite. Cela signifie que vous n'incluez pas une production qui n'est pas possible en utilisant la grammaire d'origine (car cet état n'est pas dans l'ensemble suivant)

1
Yeswantth