IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de...

42
IFT313 Introduction aux langages formels Froduald Kabanza Département d’informatique Université de Sherbrooke Analyseurs LL(1) non récursifs

Transcript of IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de...

Page 1: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 Introduction aux langages formels

Froduald Kabanza

Département d’informatiqueUniversité de Sherbrooke

Analyseurs LL(1) non récursifs

Page 2: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 2

Sujets

• Table d’analyse LL (1)

• Générateurs d’analyseurs LL(1) non récursifs

• Transformer les grammaires ambigües

• Éliminer la récursivité à gauche (left

recursion)

• Factorisation à gauche (left factoring)

Page 3: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 3

Objectifs

• Pouvoir générer une table d’analyse LL(1) pour une grammaire donnée.

• Comprendre et pouvoir décrire et simuler l’algorithme d’analyse LL (1) non récursif.

• Pouvoir transformer une grammaire non LL(1) en une grammaire

LL (1)

– Pouvoir transformer une grammaire ambigüe en une grammaire non

ambigüe.

– Pouvoir éliminer la récursivité à gauche (left recursion).

– Pouvoir utiliser la factorisation à gauche (left factoring)

Page 4: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

© Froduald Kabanza

4IFT313

Références

[1] Sudkamp, T. A.. Languages and Machines. Third Edition Edition.

Addison-Wesley, 2005.– Sections 4.3 et 19.6 à 19.7

[2] Appel, A. and Palsberg. J. Modern Compiler Implementation in Java.

Second Edition. Cambridge, 2004.– Section 3.2

[4] Aho, A., Lam, M., Sethi R., Ullman J. Compilers: Principles, Techniques, and

Tools, 2nd Edition. Addison Wesley, 2007.– Section 4.3 et 4.4.4 à 4.4.5

Page 5: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 5

Rappel : Algorithme Driver LLvariables : stack (pile), x (symbole au sommet de la pile), a (symbole d’entrée courant), in

(entrée)

initialement la pile contient $S (le symbole départ S) et l’entrée contient w$ (chaîne de tokens w).

while (true)

{ if (x = = $) && (a= = $) return true ; // on accepte la chaîne d’entrée comme étant correcte

if (x = = a) && (a != $) // match transition

{ pop a from the stack; // dépiler le symbole de la pile

a = in.read(); // lire le token (symbole) courant et avancer la tête de lecture

continue;}

if x is a nonterminal // predictive transition

{ find a production x y1 … yk; // trouver une production dont la partie gauche est x

// les essayer tous jusqu’à en trouver menant à l’acceptation (backtracking)

exit with error if no such production exists;

pop x from the stack;

push yk on the stack; …; push y1 on the stack;

continue; }

exit with error;

}

Page 6: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 6

Rappel : Nullable, First et Follow- Nullable(X) est vrai si et seulement si X peut dériver la chaîne vide en zéro

ou plusieurs étapes.

- First( ) a est l’ensemble de terminaux qui peuvent commencer une chaîne dérivée de .a

- Follow(X) est l’ensemble de terminaux qui peuvent suivre X immédiatement, dans une forme sententielle.- En plus, si X peut être le dernier symbole dans une forme sententielle,

on ajoute $ à Follow(X).

- Étant donne une chaîne , a nullable(a) si et seulement si chaque symbole de a est annulable.

- Étant donne un symbole X et une chaîne g :First(Xg)=First[X] if not nullable[X]

First(Xg)=Union(First[X], First( )) g if nullable[X]

Page 7: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 7

Définitions formelles- Une définition plus formelle de Nullable, First and Follow est que ce sont les

plus petits ensembles pour lesquels les propriétés suivantes sont valides :

If S is the start symbol, then Follow[S] contains $;

For each terminal symbol a, First(a) = { a };

For each production X Y1 … Yk

If Y1 … Yk are all nullable or (if k = 0) nullable[X] = true;

for each i from 1 to k,

if Y1… Yi-1 are all nullable (or if i=1) First[X] = Union(First[X], First[Y i]);

if Yi+1… Yk are all nullable (or if i=k) Follow[Yi] = Union(Follow[Yi], Follow[X]);

for each j from i + 1 to k

if Yi+1… Yj-1 are all nullable (or if i+1=j) Follow[Yi] = Union(Follow[Yi], First[Yj]);

- Pour obtenir les ensembles Nullable, First et Follow, on calcule le point fixe (ou la fermeture) de ces équations.

Page 8: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 8

Rappel: calculer Nullable, First et Follow

Algorithme nullableFirstFollow

initialize all entries of First and Follow to the empty set and those of nullable to false;

set Follow[S] = {$}, where S is the start symbol and $ the end marker;

for each terminal symbol a, First(a) = {a};

do {

for each production X Y1…Yk {

if Y1…Yk are all nullable or (if k = 0) nullable[X] = true;

for (i = 1; i <= k; i++) {

if Y1…Yi-1 are all nullable (or if i=1) First[X] = Union(First[X], First[Y i]);

if Yi+1…Yk are all nullable (or if i=k) Follow[Y1] = Union(Follow[Yi], Follow[X]);

for (j = i+1; j <= k; j++) {

if Yi+1…Yj-1 are all nullable (or if i+1=j) Follow[Y1] = Union(Follow[Yi], First[Yj]);

}

}

}

} while First, Follow or nullable is modified in the current iteration

Page 9: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 9

Rappel : comment prédire une production ?

- Voici les règles pour prédire une production:

Si le sommet de la pile est A, et le prochain token est a, alors on prédit la production A a telle que a est dans First(a).

Ainsi le driver LL va appliquer A , a en remplaçant A par a au sommet de la pile

Lorsque a peut dériver la chaîne vide, on prédit la règle A a si a est dans Follow(A) ou si le prochain token est $ (EOF) et $ est dans Follow(A).

- Avec ces règles, on peut générer une table d’analyse M, telle que M[A,a] contient la règle de production à appliquer lorsque A est au sommet de la pile et a est le prochain token.

Page 10: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 10

Génération de la table d’analyse LL (1)

Algorithm generateLL1ParsingTable

Entrée : grammaire G(V, T, P, S);

Sortie : table d’analyse M[symbole non terminal, symbole terminal];

Pour toutes les règles de production A a dans P

{

Pour tous les terminaux a dans First( )a // a est un élément de T

Ajouter A a to M[ , A a]; // A est un élément de V

Si nullable( ) a // quand c’est annulable, il faut aller voir ce qui peut suivre

Pour tous les terminaux a dans Follow(A)

Ajouter A a to M[ , A a]; } Mettre error dans chaque entrée de de M non définie (ne contenant pas de

règle);

Page 11: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 11

Exemple 1

- G = (V, A, R, S) :

V = {X, Y, S}

A = {a, b, c}

R = { 1. S a

2. S X Y S

3. X b 4. X Y

5. Y ε 6. Y c}

S X Y

nullable First

Follow

true truefalse

{a, b, c} {b, c} {c}

{$} {a, b, c} {a,b, c}

Table d’analyse LL(1)

a b cS

X

Y

S aS X Y S S X Y S S X Y S

$

Y ε Y εY εY c

X bX YX Y X Y

Pour chaque a dans First( )a Ajouter A a to M[ , A a]; Si nullable( ) ,a

Pour chaque a dans Follow(A)

Ajouter A a to M[ , A a];

Page 12: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 12

Exemple 2

G = (V, A, R, E) :

V = {E, E’, T, T’, F}

A = {(, ), +, *, n}

R = { E TE’

E’ + TE’ | ε

T FT’ T’ *FT’ | ε F ( ) | E

n }

E E’ T

Nullable First

Follow

true falsefalse

{(,n} {+} {*}

{), $} {+, ), $}

T’ F

true false

{(,n} {(,n}

{), $} {+, ), $}{+,*), $}

Table d’analyse

n + *E E TE’

$

E’ E’+TE’ E’ ε E’ ε

T T FT’ TFT’

T’ T’ ε T’*FT’ T’ ε T’ ε

F F n F(E)

( )

E TE’

Pour chaque a dans First( )a Ajouter A a to M[ , A a]; Si nullable( ) ,a

Pour chaque a dans Follow(A)

Ajouter A a to M[ , A a];

Page 13: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 13

Algorithme d’analyse LL(1) non récursif

- Nous pouvons maintenant mettre à jour l’algorithme LLDriver pour qu’il utilise une table d’analyse LL(1) pour prédire une production.

- Si la table d’analyse générée à partir d’une grammaire contient des entrées avec des productions multiples, la grammaire est dite non LL(1).

- Pour certaines grammaires qui ne sont pas LL(1), on peut définir des grammaires LL(1) équivalentes par de simples transformations. On en verra certaines plus loin :- Éliminer l’ambiguïté- Éliminer la récursivité à gauche- Factoriser les productions à gauche

Page 14: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 14

Algorithme d’analyse LL (1) non récursif

Algorithm LL1Parser

Entrée : - table d’analyse de la grammaire;

- chaîne d’entrée terminée par $ (fin de fichier).

Sortie : - une dérivation de la chaîne d’entrée si elle syntaxiquement correcte;

- sinon erreur.

Page 15: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 15

Algorithme d’analyse LL(1) non récursifAlgorithm LLDriver

variables : stack (pile), x (symbole au sommet de la pile), a (symbole d’entrée courant), in (entrée, suite fini de symboles, lexèmes)

initialement la pile contient $S (le symbole départ S) et l’entrée contient w$ (chaîne de tokens w).

while (true)

{ if (x = = $) && (a= = $) return true ; // on accepte la chaîne d’entrée comme étant correcte

if (x = = a) && (a != $) // match transition

{ pop a from the stack; // dépiler le symbole de la pile

a = in.read(); // lire le token (symbole) courant et avancer la tête de lecture

continue;}

if x is a nonterminal // predictive transition

{ if M[x,a] is error exit with error;

let x y1 … yk the production in M[x,a]

pop x from the stack;

push yk on the stack; …; push y1 on the stack;

continue; }

exit with error;}

Page 16: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 16

Exemple

G = (V, A, R, E) :

V = {E, E’, T, T’, F}

A = {(, ), +, *, n}

R = {

E TE’

E’ + TE’ | ε

T FT’ T’ *FT’ | ε F ( ) | E

n }

Table d’analyse

n + *

E E TE’

$

E’ E’+TE’ E’ ε E’ εT T FT’ TFT’

T’ T’ ε T’*FT’ T’ ε T’ εF F n F(E)

( )

E TE’

Page 17: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

return true

Pile

0.3.3.3.2.3.3.2.3.3.2.3.2.3.2.3.3.1.

Étape Règle Algorithm LLDriver

0. stack = ($S); a = in.read(); x=stack.top();

while (true) {

1. if (x = = $) && (a= = $)

return true ;

2. if (x = = a) && (a != $) {

pop a from stack; a = in.read();

continue;}

3. if x is a nonterminal {

if M[x,a] is error exit with error;

let x y1 … yk in M[x,a]

pop x from stack; push y on stack;

continue; }

4. exit with error;}

Entrée

Entrée : n+n*n

$E$E’T$E’T’F$E’T’n$E’T’$E’$E’ T+$E’ T$E’T’F$E’T’n$E’T’$E’T’F*$E’T’F$E’T’n$E’T’$E’$

n+n*n$ n+n*n$ n+n*n$n+n*n$ +n*n$ +n*n$ +n*n$ n*n$ n*n$ n*n$ *n$ *n$ n$ n$ $ $ $

E TE’T FT’F n

T’ εE’ +TE’

T FT’F n

T’ *FT’

F n T’ εE’ ε

n + *

E E TE’

$

E’ E’+TE’ E’ ε E’ ε

T T FT’ TFT’

T’ T’ ε T’*FT’ T’ ε T’ ε

F F n F(E)

( )

E TE’

IFT313 17© Froduald Kabanza

Page 18: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 18

Quelques considérations pratiques

- L’algorithme LL1Driver produit une dérivation de l’entrée, plus précisément une séquence de règles de production qui dérivent la chaîne d’entrée.

- Cet algorithme est essentiellement un automate à pile LL déterministe qui simule la dérivation la plus à gauche.

- Pour obtenir un processeur de langage (interpréteur ou compilateur), on peut associer les règles de production avec des actions qui seront exécutées chaque fois qu’une production est appliquée. Ces actions s’appellent des routines sémantiques ou des actions

sémantiques.

- Il faut ajouter aussi les gestions des erreurs.

Page 19: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 19

Quelques considérations pratiques

- Un générateur d’analyseur LL(1) non récursif prend comme entrée une grammaire avec des actions sémantiques et génère un parseur pour cette grammaire.

- Un tel générateur fonctionne comme suit. - Il a comme coquille le code du driver LL(1), qui est indépendant de la

grammaire.- À partir de la grammaire, il génère une table d’analyse.- Il combine ensuite le code du driver LL(1) avec la table d’analyse pour obtenir

le parseur.

- Cela vous rappelle-t-il quelque chose ? Les générateurs d’analyseurs lexicaux bien sûr. Un tel générateur emploie une

approche similaire: un scanner est obtenu en combinant un DFA driver avec une table de transitions d’un DFA obtenue d’une spécification d’expressions régulières avec des actions associées.

Page 20: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 20

Quelques considérations pratiques

- Il est possible de généraliser l’analyse LL(1) à l’analyse LL(k), pour un entier k fixé : un analyseur LL(k) prédit une production en se basant sur le symbole au sommet de la pile et les k prochains lexèmes (tokens).

- Plus k est grand, plus l’analyseur a une grande puissance d’expressivité, mais aussi plus il est compliqué à coder et souvent il est moins rapide. De plus, la table d’analyse est beaucoup plus volumineuse.

- Une grammaire est dite LL(k) si et seulement si le langage généré par la grammaire est analysable par un analyseur LL(k).

- Pour beaucoup de langages de programmation, l’analyse LL(1) suffit moyennant quelques extensions, comme l’ajout de règles de priorité.

Page 21: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 21

Transformer une grammaire ambigüe

- Nous avons vu que la grammaire suivante est ambigüe parce qu’elle produit deux arbres d’analyse différentes pour la même entrée. Donc on pourrait avoir deux dérivations les plus à gauche différentes pour la même entrée.

G = (V, A, R, Exp) :

V= {Exp}A = {(, ), +, *, num}

R = {Exp numExp ( Exp ) Exp Exp + ExpExp Exp * Exp

}

Exp

Exp * Exp

Exp +

num

numExp

num

Exp

Exp + Exp

num * Exp

num

Exp

num

Page 22: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 22

Transformer une grammaire ambigüe

- La plupart des générateurs d’analyseurs syntaxiques permettent la spécification de « règles de priorité » qui assure que la chaîne d’entrée a une seule interprétation possible.

- Toutefois, dans d’autres cas, on n’a pas d’autres choix que de réécrire la grammaire en une grammaire équivalente acceptable pour une analyse LL(1) (ou, pour plus tard, LR(1)) .

- Cependant, il n’existe pas de méthode systématique pour une telle opération de transformation de grammaire ambiguë en une grammaire non ambiguë. Il faut se servir de l’intuition et de l’expérience.

Page 23: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 23

Exemple 1 1/2- Pour obtenir une grammaire non ambigüe équivalente à la précédente,

intuitivement on aimerait spécifier que l’opérateur de multiplication (*) a une priorité sur celui d’addition (+), de sorte que num + num * num soit interprété comme num + (num * num).

- Deuxièmement, on voudrait spécifier que chaque opération est évaluée par l’associativité à gauche, de sorte que la seule interprétation possible pour num - num - num soit (num – num) – num (plutôt que num – (num – num)).

- Nous pouvons faire cela en introduisant de nouveaux symboles non terminaux et de nouvelles règle de production.

- Traditionnellement, les facteurs (F) sont les nombres qu’on multiplie et les termes (T) les nombres qu’on additionne; on introduit donc les symboles F et T pour réécrire la grammaire.

Page 24: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 24

Exemple 1 2/2

Grammaire ambigüe :

G = (V, A, R, E) :

V= {E}A = {(, ), +, *, n}

R = { E E + E

E E * E E ( E ) E n

}

Grammaire équivalente non ambigüe:

G = (V, A, R, E) :V= {E, F, T}A = {(, ), +, *, n}

R = { E E + T

E T T T * F T F

F ( E) F n

}

Page 25: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 25

Exemple 2 1/3

- Considérons la grammaire

S if E then S else S |

if E then S | other

E c

- Cette grammaire est ambiguë que l’instruction

if c1 then if c2 then s1 else S2

a deux arbres de dérivation.

- L’interprétation habituelle du « if then else »

est que «chaque else est associé au plus récent if sans else correspondant». Cette interprétation correspond au premier arbre.

S

Ethen

Sif

c1E

thens1

if

c2

elses2

Ethenif

c1

elses2

S

S

Ethen

S1if

c2

Page 26: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 26

Récursivité à gauche (left recursion)- La nouvelle grammaire n’est pas ambigüe. Il y a toujours un seul arbre

d’analyse possible pour une chaîne de lexèmes (tokens) du langage.

- Toutefois, la nouvelle grammaire n’est pas pratique pour l’analyse LL(1). Les productions E E + T | T vont causer des entrées multiples dans la table d’analyse LL(1), vu que tout token dans First(T) sera aussi dans First(E + T).

- Le problème est que E apparaît comme premier symbole de la partie droite d’une production commençant par E. Ça s’appelle la récursivité à gauche (left-recursion).

- Plus précisément, une grammaire est dite récursive à gauche (left-recursive) si elle a un non terminal A tel qu’il est possible d’avoir une dérivation A => A .a

- L’analyse descendante ne peut pas gérer la récursivité à gauche. Par conséquent, il nous faut une transformation permettant de passer d’une grammaire récursive à gauche à une grammaire non récursive à gauche.

Page 27: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 27

Éliminer la récursivité à gauche- Pour éliminer la récursivité à gauche pour les productions E E + T | T , on les

réécrit avec une récursivité à droite. Plus précisément, on introduit un nouveau non-terminal E’ et on écrit :

E TE’ E’ +TE’ E’ ε

- De manière plus systématique, chaque fois qu’on a deux productions X X g et X , a cela veut dire qu’elle génèrent le langage décrit par l’expression régulière

ag*, c’est à dire, un a suivi par zéro ou plusieurs g. On peut réécrire cette expression régulière par des productions récursives à droite comme suit :

X a1 X’X a2 X’X’ g1 X’X’ g2 X’ X’ ε

X Xg1

X a1

X Xg2

X a2

devient

Page 28: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 28

Exemple

- Grammaire récursive à gauche :

G = (V, A, R, E) :V= {E, F, T}A = {(, ), +, *, n}

R = { E E + T

E T T T * F T F

F ( E) F n

}

Grammaire équivalente non récursive à gauche:

G = (V, A, R, E) :

V = {E, E’, T, T’, F}

A = {(, ), +, *, n}

R = {

E TE’

E’ + TE’ | ε

T FT’ T’ *FT’ | ε F ( ) | E n}

Page 29: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 29

Factorisation à gauche

- Une situation un peu similaire à la récursivité à gauche est lorsque deux productions ayant la même partie gauche ont des parties droites ayant un préfixe commun. Cela conduit à des entrées multiples dans la table d’analyse LL(1).

- Cs-à-d., si la grammaire contient deux production A 1 | 2 , si l’entrée

contient une chaîne non vide dérivée de , on ne peut pas savoir s’il faut dériver A vers 1 ou vers 2.

- Cependant on peut différer la décision, en dérivant A vers X, où X est un nouveau non-terminal. Une fois que nous avons scannée l’entrée dérivée de , on peut alors dériver X vers 1 ou vers 2. Autrement dit, peut factoriser la grammaire à

gauche, en introduisant un nouveau non terminal pour représenter le suffixe sur lequel les deux productions diffèrent, comme suit :

A X X 1 | 2

Page 30: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 30

Exemple de factorisation à gauche 1/3

- Soit la grammaire S if E then S else S | if E then S | other

E num- Nous avons vu que cette grammaire est ambiguë. Nous avons vu aussi une

grammaire non ambiguë équivalente.

- Au lieu de travailler avec la grammaire non ambiguë équivalente, on pourrait factoriser la grammaire à gauche, comme suit :

S ® if E then S X | other

X ® else S | ε

E num- Cette grammaire est équivalente. Elle est toujours ambiguë. Elle va donc

générer un conflit dans la table d’analyse LL(1). Par contre, c’est un conflit plus facile à gérer comparé au conflit dans la grammaire d’origine.

Page 31: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 31

Exemple de factorisation à gauche 2/3

- En effet la table d’analyse de la grammaire

S ® if E then S X | other

X ® else S | ε

E c

est

- L’entrée [X, else] a un conflit reflétant l’ambiguité dans le choix de la règle de pruction à utiliser pour X lorsque le prochain token est else.

other c else if then $

S S ® other S ® if E then S X

XX ® else S X ® ε

X ® ε

E E num

Page 32: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 32

Exemple de factorisation à gauche 3/3

- L’entrée [X, else] a un conflit reflétant l’ambiguité dans le choix de la règle de pruction à utiliser pour X lorsque le prochain token est else.

- On peut résoudre cet ambiguïté, en retant juste la règle X ® else S dans l’entrée [X, else]. Cela revient associer else avec le plus récent then.

other c else if then $

S S ® other S ® if E then S X

XX ® else S X ® ε

X ® ε

E E c

Page 33: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 33

Stratégies de recouvrement d’erreurs- Une erreur apparaît lorsque la chaîne d’entrée n’est pas syntaxiquement

correcte :- Soit on a un token au sommet de la pile, mais il diffère de celui à

l’entrée- Soit on a un non terminal x au sommet de la pile et M[x,a] est vide.

- En pratique, on ne veut pas arrêter l’analyse à la toute première erreur. Aimeriez-vous un compilateur qui vous donne uniquement une seule

erreur à la fois ? On veut continuer l’analyse syntaxique jusqu’à un certain nombre

d’erreurs ou jusqu’à un certain niveau de sévérité d’erreur.- Les stratégies de recouvrement typiques consistent à réparer la chaîne

d’entrée pour que l’analyse continue. En particulier, on pourrait:- Insérer des tokens supposément manquants.- Supprimer des tokens supposément de trop.- Remplacer des tokens supposément erronés.

Page 34: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 34

Stratégies de recouvrement

Algorithm LLDriver

variables : stack (pile), x (symbole au sommet de la pile), a (symbole d’entrée courant), in (entrée)

initialement la pile contient $S (le symbole départ S) et l’entrée contient w$ (chaîne de tokens w).

while (true)

{ if (x = = $) && (a= = $) return true ; // on accepte la chaîne d’entrée comme étant correcte

if (x = = a) && (a != $) // match transition

{ pop a from the stack; // dépiler le symbole de la pile

a = in.read(); // lire le token (symbole) courant et avancer la tête de lecture

continue;}

if x is a nonterminal // predictive transition

{ if M[x,a] is empty error(x,a); // recouvrement d’erreur

let x y1 … yk the production in M[x,a]

pop x from the stack;

push yk on the stack; …; push y1 on the stack;

continue; }

error(x,a);} // recouvrement d’erreur

Page 35: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 35

Insertion de tokens manquants- Pour insérer un token manquant de l’input, on n’a pas besoin de l’ajouter

explicitement à la chaîne d’entrée.

- Il suffirait de prétendre que le token est présent, imprimer un message approprié et continuer normalement.

- Pour ce cas, la fonction error(x,a) pourrait procéder comme suit :- Si x, le symbole au sommet de la pile, est un token, afficher le message

“Expected ‘x’ on the input”.

- Si x est un non terminal, afficher le message “Expected, ‘a1’, …, ‘an’ on

the input”, tel que ‘ai’ sont les tokens pour lesquels l’entrée M[x, ai] est

définie (l’entrée dans la table M est non vide).- Dépiler et lire le prochain token :

- pop x from the stack; - a = in.read();

Page 36: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

Report the error

Pile

0.3.3.3.3.

3.2.3.3.2.3.2.3.2.3.3.1.

Étape Règle Algorithm LLDriver

0. stack = ($S); a = in.read(); x=stack.top();

while (true) {

1. if (x = = $) && (a= = $)

return true ;

2. if (x = = a) && (a != $) {

pop a from stack; a = in.read();

continue;}

3. if x is a nonterminal {

if M[x,a] is error exit with error;

let x y1 … yk in M[x,a]

pop x from stack; push y on stack;

continue; }

4. exit with error;}

Entrée

Entrée : n n*n

$E$E’T$E’T’F$E’T’n$E’T’

$E’T’$E’$E’ T+$E’ T$E’T’F$E’T’n$E’T’$E’T’F*$E’T’F$E’T’n$E’T’$E’$

n n*n$ n n*n$ n n*n$n n*n$ n*n$ Error : expected +, *, ), or $  +n*n$ On suppose le + +n*n$ n*n$ n*n$ n*n$ *n$ *n$ n$ n$ $ $ $

E TE’T FT’F n

T’ εE’ +TE’

T FT’F n

T’ *FT’

F n T’ εE’ ε

n + *

E E TE’

$

E’ E’+TE’ E’ ε E’ ε

T T FT’ TFT’

T’ T’ ε T’*FT’ T’ ε T’ ε

F F n F(E)

( )

E TE’

IFT313 36© Froduald Kabanza

Exemple 1

Page 37: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

Report the error

Pile

0.3.3.3.2.3.3.2.

3.3.2.3.2.3.2.3.3.1.

Étape Règle Algorithm LLDriver

0. stack = ($S); a = in.read(); x=stack.top();

while (true) {

1. if (x = = $) && (a= = $)

return true ;

2. if (x = = a) && (a != $) {

pop a from stack; a = in.read();

continue;}

3. if x is a nonterminal {

if M[x,a] is error exit with error;

let x y1 … yk in M[x,a]

pop x from stack; push y on stack;

continue; }

4. exit with error;}

Entrée

Entrée : n+*n

$E$E’T$E’T’F$E’T’n$E’T’$E’$E’ T+$E’ T

$E’T’F$E’T’n$E’T’$E’T’F*$E’T’F$E’T’n$E’T’$E’$

n+*n$ n+*n$ n+*n$ n+*n$ +*n$ +*n$ +*n$ *n$ Error: expected n or (. n*n$ Si on suppose n. n*n$ *n$ *n$ n$ n$ $ $ $

E TE’T FT’F n

T’ εE’ +TE’

T FT’F n

T’ *FT’

F n T’ εE’ ε

n + *

E E TE’

$

E’ E’+TE’ E’ ε E’ ε

T T FT’ TFT’

T’ T’ ε T’*FT’ T’ ε T’ ε

F F n F(E)

( )

E TE’

IFT313 37© Froduald Kabanza

Exemple 2

Page 38: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

Pile

0.3.3.3.2.3.3.2.

3.3.2.

3.

.

.

.

Étape Règle Algorithm LLDriver

0. stack = ($S); a = in.read(); x=stack.top();

while (true) {

1. if (x = = $) && (a= = $)

return true ;

2. if (x = = a) && (a != $) {

pop a from stack; a = in.read();

continue;}

3. if x is a nonterminal {

if M[x,a] is error exit with error;

let x y1 … yk in M[x,a]

pop x from stack; push y on stack;

continue; }

4. exit with error;}

Entrée

Entrée : n+*n

$E$E’T$E’T’F$E’T’n$E’T’$E’$E’ T+$E’ T

$E’T’F$E’T’)E($E’T’)E

$E’T’)E

.

.

.

n+*n$ n+*n$ n+*n$ n+*n$ +*n$ +*n$ +*n$ *n$ Error: expected n or (. (*n$ Si on suppose (. (*n$ *n$ Error: expected n or (. n*n$ Si on suppose n.

.

.

.

E TE’T FT’F n

T’ εE’ +TE’

T FT’F n

.

.

.

n + *

E E TE’

$

E’ E’+TE’ E’ ε E’ ε

T T FT’ TFT’

T’ T’ ε T’*FT’ T’ ε T’ ε

F F n F(E)

( )

E TE’

IFT313 38© Froduald Kabanza

Exemple 3

Page 39: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 39

Recouvrement d’erreurs par insertion de tokens

- Le recouvrement d’erreur par insertion de tokens est à utiliser avec précaution parce que une cascade d’erreurs risque de mener à une situation où les tokens sont insérés (plus exactement, sont supposés présents) indéfiniment, de sorte que la chaine d’entrée n’est jamais vidée, c-à-d., menant à une boucle sans fin.

Page 40: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 40

Recouvrement d’erreurs par suppression de tokens

- Le recouvrement d’erreur par suppression de tokens est plus sécuritaire parce qu’il garantie toujours que la chaîne d’entrée va être vidée.

- Étant donné x, le symbole au sommet de la pile, la stratégie est, en cas d’erreur, de sauter (supprimer) les prochains tokens jusqu’au premier token x, si x est un token, ou jusqu’au premier token dans dans Follow(x) si x est un non terminal.

- Pour ce cas, la fonction error(x,a) va procéder comme suit :- Si x, le symbole au sommet de la pile, est un token, afficher le message

“Expected ‘x’ on the input”.

- Si x est un non terminal, afficher le message “Expected, ‘a1’, …, ‘an’ on the input”,

tel que ‘ai’ sont les tokens pour lesquels l’entrée M[x, ai] est définie (non vide).

- Dépiler x; - Si x est un token, avancer la tête de lecture juste après le prochain token x (c-à-

d., a devient ce token).- Si x est un non terminal, avancer la tête de lecture jusqu’au prochain token dans

Follow(x) (c-à-d., a devient ce token).

Page 41: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

Pile

0.3.3.3.2.3.3.2.

3.1.

Étape Règle Algorithm LLDriver

0. stack = ($S); a = in.read(); x=stack.top();

while (true) {

1. if (x = = $) && (a= = $)

return true ;

2. if (x = = a) && (a != $) {

pop a from stack; a = in.read();

continue;}

3. if x is a nonterminal {

if M[x,a] is error exit with error;

let x y1 … yk in M[x,a]

pop x from stack; push y on stack;

continue; }

4. exit with error;}

Entrée

Entrée : n+ *n

$E$E’T$E’T’F$E’T’n$E’T’$E’$E’ T+$E’ T

$E’$

n+*n$ n+*n$ n+*n$ n+*n$ +*n$ +*n$ +*n$ *n$ Error: expected n or (. *n$ Avancer jusqu’à au prochain terminal dans Follow de E’ $ $

E TE’T FT’F n

T’ εE’ +TE’

E’ ε

n + *

E E TE’

$

E’ E’+TE’ E’ ε E’ ε

T T FT’ TFT’

T’ T’ ε T’*FT’ T’ ε T’ ε

F F n F(E)

( )

E TE’

IFT313 41© Froduald Kabanza

Exemple 4

Report the error

Page 42: IFT313 Introduction aux langages formels Froduald Kabanza Département dinformatique Université de Sherbrooke Analyseurs LL(1) non récursifs.

IFT313 © Froduald Kabanza 42

Résumé

- Nous avons vu un nouvel algorithme pour l’analyse syntaxique non récursive, LL1Driver.

- Il utilise une table d’analyse, générée à partir de la grammaire.- Des transformations peuvent être nécessaires pour avoir grammaire LL(1).

- Au lieu du driver LL1 et de la pile, on peut écrire un analyseur syntaxique en considérant chaque règle de production comme un appel de fonction qui implémente une étape de dérivation et en « matchant » les tokens chaque fois qu’ils apparaissent dans une dérivation.

- Ceci donne lieu à un analyseur descendant récursif. - La table d’analyse LL(1) demeure toujours nécessaire même dans ce cas. - C’est l’approche utilisée par JavaCC. Nous la verrons à la leçon suivante.