méthode LR(1)
Transcription
méthode LR(1)
Compilateurs - notes séance 10 Gérard Dethier 2009–2010 Préambule Ce document reprend des notes prises à la dixième séance du cours de « Compilateurs » (INFO0085-1) donné par le professeur Xavier Boyen le mardi 27/04/2010. 1 Rappel sur la méthode SLR Un item LR(0) est composé d’une règle de production et d’un marqueur et est noté : [A -> α . βγ] où le point est un marqueur. Dans la méthode SLR, on construit un DFA dont les états sont des ensembles d’items. Un chemin parcouru dans l’automate correspond à tous les préfixes viables que l’on peut rencontrer dans une dérivation la plus à droite. Un préfixe est viable lorsqu’on n’a pas encore rencontré d’erreur. Se trouver en un état du DFA signifie qu’on a rencontré un préfixe viable qui correspond à un des items de l’état. 2 Méthode LR(1) canonique La méthode canonique capture toutes les grammaires LR(1). L’ensemble des grammaires SLR(1) est inclus dans l’ensemble des grammaires LR(1). La méthode SLR n’est cependant pas assez puissante pour représenter certains types de grammaires pourtant simples. Exemple de conflit dans la méthode SLR : [A -> α . a β ] => shift sur le a [A -> γ . ] et a ∈ FOLLOW(A) => reduce sur le a Si ces deux items appartiennent au même état, on a un conflit. Il se peut que le deuxième item ne soit possible que dans un certain contexte dans lequel il n’y a pas de shift possible. Générer des reduce pour tous les a ∈ follow(A) est donc potentiellement une source de conflits inexistants en pratique. Soit la grammaire suivante qui représente une assignation : S -> L = R S -> R L -> * R L -> id R -> L 1 Cette grammaire n’est pas SLR(1), il n’est pas possible de construire une table d’analyse SLR sans conflit au niveau des actions : Imaginons que l’on soit dans un état s contenant l’item [R -> L.]. On a alors que action[s, ’=’] vaut "reduce" or cette situation n’arrive jamais dans une dérivation valide. La méthode canonique LR(1) utilise des items canoniques LR(1) (et plus LR(0) comme c’est le cas pour la méthode SLR), on ajoute un symbole de lookahead aux items : [A -> α . β, a] où a correspond à un symbole de lookahead (le préfixe viable correspondant est suivi directement par le symbole a). Si on reprend le cas problématique des méthodes SLR avec l’item [A -> γ .] nécessitant des reduce pour tous les a ∈ follow(A), la méthode LR(1) permet de "particulariser" et de ne générer de reduce que sur le sous-ensemble utile de follow(A). Dans le contexte de la grammaire présentée précédemment, il n’y a alors plus de conflit. 2.1 Construction de l’ensemble des items canoniques LR(1) in : G’ (grammaire augmentée, voir méthode SLR) out : Une collection C d’ensembles Ii d’items LR(1) valides pour au moins un préfixe viable dans G’ avec C = {I0 , I1 , ..., In } 2.1.1 Fermeture Soit un ensemble d’items associé à une configuration valide, la fermeture de cet ensemble contient tous les items associés à cette même configuration valide. Soit la notation suivante : ... ( α | β ) a ... où α est un préfixe viable, αβ un handle et a un symbole de lookahead. Soit une configuration viable (résultat d’une dérivation valide) : ... (α | B β) a ... Si on a une prod. B -> γ alors ... (α | γ β) a ... Si en plus b ∈ FIRST(βa) alors ... (α | γ b β 0 ) a ... et le préfixe est donc viable aussi pour l’item [B -> . γ, b]. D’où l’algorithme suivant : function closure(I : set of LR(1) items) : set of LR(1) items; repeat if \exists item [A -> \alpha . B \beta, a] \in I and \exists prod B -> \gamma \in G’ and \exists term. b \in FIRST(\beta a) such as [B -> .\gamma, b] \notin I then I := I \union {[B -> .\gamma, b]} until "No more items can be added to I" 2.1.2 Goto Soit un ensemble d’items associé au préfixe viable et au handle suivants : ... (α | X β ) a On cherche l’ensemble d’items correspondant au préfixe viable et au handle suivants : ... (α X | β ) a Algorithme : 2 function goto(I : set of LR(1) items, X : NT) J := {[A -> \alpha X . \beta, a] such as [A -> \alpha X . \beta, a] \in I} return closure(J) 2.1.3 Construction de C procedure items(G’ : extended grammar) : set of LR(1) items set; I_0 := closure({[S’ -> . S, $]}); C := {I_0} repeat if \exists I \in C and \exists symb. X tels que goto(I, X) \neq 0 and goto(I, X) \not\in C then "ajouter goto(I, X) à C" until "convergence" 2.2 Contruction de la table d’analyse canonique LR(1) in : Grammaire étendue G’ out : tables actions et goto 1. Construire C = I0 , I1 , ..., In pour G’ 2. Construction de la table actions : (a) Créer état i pour chaque Ii (b) Définir les actions pour l’état i : i. Si [A -> α . a β, b] ∈ Ii et goto(Ii , a) = Ij et a est terminal, alors actions[i, a] := "shift j" ii. Si [A -> α ., a] ∈ Ii pour A 6= S’, alors actions[i, a] := "reduce A -> α" iii. Si [S’ -> S ., $] ∈ Ii , alors actions[i, $] := "accept" 3. Pour tout Ii et A, si goto(Ii , A) = Ij , alors goto[i, A] := j. 4. Initialiser toutes les entrées des tables actions et goto non définies à "error". L’état initial utilisé par l’analyseur est celui construit à partir de [S’ -> .S, $] (I0 par construction). En cas de conflit, la grammaire n’est pas LR(1). 3 Discussion de la méthode LR(1) canonique La méthode LR(1) canonique a un inconvénient par rapport à la méthode SLR : un nombre d’états plus élevé d’où des tables d’analyse plus grandes. Par exemple, le langage Pascal requiert quelques centaines d’états avec la méthode SLR mais plusieurs milliers avec la méthode LR(1) canonique. Une méthode intermédiaire, appelée LALR, ne requiert pas plus d’états que la méthode SLR mais est plus puissante que celle-ci (tout en restant plus faible que la méthode LR(1) canonique). Les méthodes SLR et LR(1) peuvent être comparées par rapport aux états du DFA servant de base à la constructions des tables d’analyse : – SLR : les états sont des ensembles d’items LR(0) – LR(1) canonique : les états sont des ensembles d’items LR(1) 3 Avec la méthode LALR, les états sont des ensembles d’items LR(1) mais on va fusionner les états dont les items sont les mêmes au symbole de lookahead près (soit l’item LR(1) [A -> α . β, a], l’item suivant est identique au symbole de lookahead près : [A -> α . β, b]). À noter qu’avec des machines modernes, la méthode LR(1) canonique est devenue adéquate. 4