Analyse Syntaxique

Programming, Linguistics · course

Chapitre

3

ANALYSE SYNTAXIQUE

0. INTRODUCTION

Tout langage de programmation possède des règles qui indiquent la structure syntaxique d'un

programme bien formé. Par exemple, en Pascal, un programme bien formé est composé de blocs,

un bloc est formé d'instructions, une instruction est formée de ... La syntaxe d'un langage peut être

décrite par une grammaire. Lors de l’analyse syntaxique, le compilateur reçoit une séquence de

jetons (jeton = (unité lexicale, lexème)), identifiées lors de l'analyse lexicale, et vérifie si cette

séquence peut être engendrée par la grammaire du langage. Cette séquence représente, en fait, un

mot.

Le problème est donc :

(i) Etant donnée une grammaire G

(ii) Etant donné une mot m (un programme)

Est ce que m appartient au langage généré par G?

Pour répondre à cette question, on construit un arbre de dérivation (AD) associé à m en

utilisant la grammaire G. Il existe deux manières pour faire cette construction :

(i) Soit en faisant une analyse descendante,

(ii) Soit en faisant une analyse ascendante.

Dans les deux cas de figures, cette construction est basée sur la grammaire du langage généré

par G.

1. GRAMMAIRES ET ARBRES DE DERIVATION

Etant donné un langage, comment décrire tous les mots appartenant de ce langage? Ou encore,

Comment décrire ce langage?

On a déjà vu les Langages Réguliers (LR), qui s'expriment à l'aide d'Expressions Régulières

(ER). Mais dans la plupart des cas, les langages ne sont pas réguliers et ne peuvent pas s'exprimer

sous forme d'une ER. A titre d’exemple, le langage des systèmes de parenthèses bien formés ne

peut pas s'exprimer par une ER. On a donc besoin d'un outil plus puissant : les grammaires.

1.1. Grammaires

Commençons par donner quelques exemples de grammaires.

Analyse Syntaxique

19

Exemple : Dans le langage naturel, une phrase est composée d'un sujet suivi d'un verbe suivi

d'un complément (pour simplifier ...), e.g. :

L'étudiant subit un cours

On dira donc :

phrase = sujet verbe complément

Ensuite, il faut expliquer ce qu'est un sujet, un verbe, un complément :

sujet = article adjectif nom | article nom adjectif | article nom

article = le | la | un | des| l'

adjectif = malin | stupide | couleur

couleur = vert | rouge | jaune

... etc.

Exemple : Une expression conditionnelle en C est : if (expression) instruction, e.g. :

if (x<10) a=a+b

Il faut encore définir ce qu'est une expression et ce qu'est une instruction ...

On distingue les

(i) Symboles terminaux : les symboles du langage (le, la, if ...)

(ii) Symboles non-terminaux : les symboles qu'il faut encore définir (ceux en italique dans les

exemples précédents)

Définition : Une grammaire G est un quadruplet (VT,VN,S,P) tel que :

 VT est un ensemble non vide de symboles terminaux,

 VN est un ensemble de symboles non-terminaux, avec VT∩VN=Ø,

 S est un symbole initial  VN, appelé axiome,

 P est un ensemble de règles productions, appelées aussi règles de réécritures.

Définition : Une règle de production α → β exprime le fait que le symboles α, αVN, peut être

remplacé par la séquence de symboles β, β(VTVN)*.

Le symbole α est appelée partie gauche de la règle de production, et la séquence de symboles β

partie droite de la règle de production. La notation utilisée, ci-dessus, pour représenter une règle de

production est appelée notation Backus-Naur Form (BNF).

Définition : L’axiome d’une grammaire est le symbole non terminal à partir duquel doit

commencer toute dérivation.

Exemple :

VT ={a, b}

VN={S}

S

P={S → ε, S → aSb}, ou encore, P={S → ε | aSb}

Exemple : G=(VT,VN,S,P) avec :

VT ={il, elle, parle, est, devient, court, reste, sympa, vite, …}

VN ={phrase, pronom, verbe, complément, verb_état, verb_action}

Analyse Syntaxique

20

S= phrase

P={PHRASE → PRONOM VERBE COMPLEMENT,

PRONOM → il | elle,

VERBE → VERB_ETAT | VERB_ACTION,

VERB_ETAT → est | devient | reste,

VERB_ACTION → parle | court,

COMPLEMENT → sympa | vite}

Conventions :

(i) L'emploi de lettres en majuscule est réservé pour dénoter des symboles non-terminaux.

(ii) Les lettres minuscules du début de l'alphabet sont utilisées pour représenter des symboles

terminaux (a, b, c, … ).

(iii) Les lettres minuscules de la fin de l'alphabet ( ... , x, y, z) sont utilisées pour indiquer une

chaîne de symboles terminaux.

(vi) Les lettres grecques dénotent des chaînes composées de symboles terminaux et non-

terminaux.

1.2. Arbre de Dérivation

Commençons par quelques définitions.

Définition : On appelle dérivation l'application d'une ou plusieurs règles à partir d'un mot de

(VTVN)+. On notera → une dérivation obtenue par application d'une seule règle de production, et

une dérivation obtenue par l'application de n règles de production, où n0.

Exemples :

S → ε S→aSb aSb→aaSbb S

S

aaabbb S

aaSbb

ab

PHRASE → SUJET VERBE COMPLEMENT

PHRASE

il parle vite PHRASE

elle est sympa

elle VERB_ETAT sympa

Remarque : Il est possible de générer des phrases syntaxiquement correctes mais qui n'ont pas

de sens. C'est lors de l'analyse sémantique que le compilateur s’occupe de ce genre de problèmes.

Définition : Etant donnée une grammaire G, le langage généré par G est l’ensemble {w(VT)*

tq S

w} et sera noté L(G)

Exemple : Si G=(VT,VN,S,P) où :

VT ={a, b}

VN={S}

S est l’axiome

P={S → ε, S → aSb}, ou encore, P={S → ε | aSb} alors L(G)={anbn, n0}.

Définition : Un Arbre de Dérivation (AD) est un arbre tel que :

(i) La racine est l'axiome,

(ii) Les feuilles sont des unités lexicales ou ε,

(iii) Les nœuds sont des symboles non-terminaux,

Analyse Syntaxique

21

(iv) Les fils d'un nœud α sont β0β1, …, βn, si et seulement si, α → β0β1, …, βn est une règle

de production.

Définition : Soit G une grammaire, une dérivation gauche (resp. droite) d’une séquence de

symboles α consiste à appliquer une règle de production de G sur le symbole non-terminal de α le

plus à gauche (resp. droite).

Exemple : Soit la grammaire ayant S pour axiome et pour règles de production P={S → aTb | c,

T → cSS | S}. Un arbre de dérivation pour le mot accacbb est :

Les dérivations gauches de S générant m sont :

S → aTb → acSSb → accSb → accaTbb → accaSbb → accacbb

Les dérivations droites de S générant m sont :

S → aTb → acSSb → acSaTbb → acSaSbb → acSacbb → accacbb

Un AD associé à m est le suivant :

Remarque : Les deux dérivations donnent le même arbre de dérivation.

Définition : Une grammaire G est ambiguë s'il existe un mot de L(G) ayant plusieurs AD.

Exemple : Voici une grammaire G ambiguë donnée par :

INSTR → if (EXPR) INSTR else INSTR | if (EXPR) INSTR | …

EXPR → …

Cette grammaire est ambiguë car le mot m= if (x>10) if (y<10) a=1 else a=0 possède deux AD

différents :

Analyse Syntaxique

22

Car on a deux interprétations syntaxiques possibles :

if (x>10) if (x>10)

if (y<0) if (y<0)

a=1 a=1

else // finsi

a=0 else

// finsi a=0

// finsi // finsi

Dans le premier cas, le else dépend du second if alors que dans le second cas, le else dépend du

premier.

2. MISE EN OEUVRE DE L’ANALYSE SYNTAXIQUE

Lors de l'analyse syntaxique le compilateur reçoit, en entrée, une séquence de jetons (jeton =

(unité, lexème)) d'unités lexicales. En sortie, il doit dire si cette séquence, qui représente un mot, est

syntaxiquement correct, i.e., si c'est un mot du langage généré par la grammaire. Il doit donc

essayer de construire l’AD de ce mot. S'il y arrive, alors le mot est syntaxiquement correct, sinon il

est incorrect. Comme nous l’avons dit précédemment, Il existe deux manières pour faire cette

construction :

(i) Soit en faisant une analyse descendante,

(ii) Soit en faisant une analyse ascendante.

2.1. Analyse Descendante

Définissons, d’abord, une analyse descendante.

Définition : Une analyse descendante consiste à construire l'AD du haut vers le bas. Le haut

étant la racine, i.e., l'axiome de la grammaire du langage. Le bas étant les feuilles, i.e., lexèmes.

Quand la grammaire est LL(1), une technique d’analyse descendante consiste à construire une

table d'analyse LL(1). Cette construction passe par celles des ensembles premier et suivant.

2.1.1. Calcul de premier

Commençons par définir l’ensemble premier associé à un symbole non-terminal.

Définition : Si X est un symbole non terminal alors l’ensemble premier associé à X est

l'ensemble de tous les symboles terminaux qui peuvent commencer une séquence de symboles

dérivée de X. Si X est un symbole terminal alors l’ensemble premier associé à X est {X}.

Exemple : Soit la grammaire représentée par les règles de production suivantes :

S → Ba

B → cP | bP | P | ε

P → dS

On a alors :

S

S

S

S

a, donc apremier(S)

cPa, donc cpremier(S)

bPa, donc b premier(S)

dSa, donc d premier(S)

Analyse Syntaxique

23

D’où, premier(S)={a, b, c, d}

Publicité

Voici un algorithme pour générer les ensembles premiers associés aux symboles d’une

grammaire.

Algorithme premier (Données G=(VT,VN,S,P) : grammaire ; Résultat premier(S) : ensemble

de symboles terminaux)

début

pour tout X, X VT, faire

premier(X) :={X}

ffaire

// 1ère étape, symboles terminaux

pour tout X, (X → Y1Y2 … Yn)P, faire

// 2ème étape, symboles non terminaux

premier(X) := premier(Y1)\{ε}

pour j, j{2, 3, … , n}, faire

si  i, 1≤i≤j-1, on a εpremier(Yi) alors

premier(X) := premier(X)  premier(Yj)\{ε}

fsi

ffaire

si  i, 1≤i≤n, on a εpremier(Yi) alors

premier(X) := premier(X)  {ε}

fsi

si (X → ε) P alors premier(X) := premier(X)  {ε} fsi

ffaire

retourner(premier(S))

fin

(1)

(2)

(3)

(4)

Appliquons cet algorithme sur les exemples suivants.

Exemple : Soit la grammaire des expressions arithmétiques, représentée par les règles de

production suivantes :

E → TE’

E’ → +TE’ | ε

T → FT’

T’ → *FT’ | ε

F → (E) | nb

On a alors :

premier(E) = premier(T)

premier(E’) = {+, ε}

premier(T) = premier(F)

premier(T’) = {*, ε }

premier(F) = {(, nb}

Exemple :

S → ABC

A → aA | ε

B → bB | cB | ε

C → de | da | dA

On a alors :

Analyse Syntaxique

24

premier(S) = premier(A)  premier(B)  premier(C) \ {ε}

premier(A) = {a, ε}

premier(B) = {b, c, ε}

premier(C) = {d}

D’où premier(S) = {a, b, c, d}

2.1.2. Calcul de suivant

Commençons par définir l’ensemble suivant associé à un symbole non-terminal.

Définition : L’ensemble suivant associé à un symbole non-terminal X est l'ensemble de tous les

symboles terminaux x qui peuvent apparaître immédiatement à droite de X dans une dérivation.

Voici un algorithme pour générer les ensembles suivants associés aux symboles d’une

grammaire.

Algorithme suivant (Données G=(VT,VN,S,P) : grammaire ; Résultat suivant(S) : ensemble

de symboles terminaux)

début

pour tout X, XVN, faire suivant(X):= {$} ffaire // $ est un marqueur de fin de chaîne

pour toute règle R, RP, faire

si R est de la forme A → αBβ, BVN, alors

suivant(B) := suivant(B)  premier(β)\{ε}

fsi

si R est de la forme A → αB, BVN, alors

suivant(B) := suivant(B)  suivant(A)

fsi

si R est de la forme A → αBβ, BVN, avec εpremier(β) alors

suivant(B) := suivant(B)  suivant(A)

(1)

(2)

(3)

fsi

ffaire

retourner(suivant (S))

fin

Exemple :

S → Sc | Ba

B → Pa | bPb | P | ε

P → dS

a, b, c suivant(S) car on a les dérivations suivantes :

S

dSa et S

bdSba

Sc, S

Exemple: Soit la grammaire des expressions arithmétiques, représentée par les règles de

production suivantes :

E → TE’

E’ → +TE’ | ε

T → FT’

T’ → *FT’ | ε

F → (E) | nb

On a alors :

Analyse Syntaxique

25

suivant(E) = { $, ) }

suivant(E’) = { $, ) }

suivant(T) = { +, ), $ }

suivant(T’) = { +, ), $ }

suivant(F) = { *, ), +$ }

Exemple :

S → aSb | cd | Sae

A → aAdB | ε

B → bb

premier suivant

S

A

B

a c

$ b a

aε

b

d

d

2.1.3. Construction de la Table d'Analyse LL(1)

Donnons, d’abord, une définition d’une table d'analyse LL(1).

Définition : Une table d'analyse LL(1) est un tableau M à deux dimensions qui indique pour

chaque symbole non-terminal A et chaque symbole terminal a ou symbole $ la règle de production

à appliquer.

Algorithme table d'analyse (Données G=(VT,VN,S,P) : grammaire ; Résultat M : tableau à

deux dimensions)

Début

(i) pour chaque règle de production A → α faire

(i.i) pour tout apremier(α) et α≠ε faire

M[A,a] := M[A,a]  { A → α }

ffaire

(i.ii) si εpremier(α) alors

pour chaque bsuivant(A) faire

M[A,b] := M[A,b]  { A → α }

ffaire

fsi

ffaire

(ii) pour chaque case M[A,a] faire

si M[A,a] = Ø alors afficher(‘erreur syntaxique’) fsi

ffaire

Fin

Exemple : Pour la grammaire des expressions arithmétique, représentée par les règles de

production suivantes :

Analyse Syntaxique

26

E → TE’

E’ → +TE’ | ε

T → FT’

T’ → *FT’ | ε

F → (E) | nb

En appliquant l’algorithme précédent, on obtient la table d'analyse LL(1) suivante :

nb

+

*

(

)

$

E E → TE’

E → TE’

E'

E’ → +TE’

E’ → ε E’ → ε

T T → FT’

T'

F

F → nb

T → FT’

T’ → ε

T’ → *FT’

T’ → ε T’ → ε

F → (E)

2.1.4. Analyse Syntaxique

Maintenant qu'on a la table d'analyse LL(1), comment l'utiliser pour déterminer si un mot m

donné appartient au langage, i.e., tel que S

m?

Pour répondre à cette question, on applique l’algorithme suivant Ceci se fait en utilisant une

pile.

Algorithme Analyse Syntaxique (Données m : mot, M : table d'analyse LL(1) ;

Résultat réponse : (accepter, refuser)

// initialisation de la pile. S étant la tête

// ps pointe sur la 1ère lettre de m

// autre≠accepter et autre≠refuser

Début

pile := [$, S]

ps :=adresse de la 1ère lettre de m

réponse=autre

Publicité

répéter

Soit X le symbole en sommet de pile

Soit a la lettre pointée par ps

si X est un non terminal alors

si M[X,a] = X → Y1Y2 … Yn alors

dépiler(X)

Pour i=n bas 1 faire

empiler(Yi)

ffaire

retourner(X → Y1Y2 … Yn)

sinon

réponse=refuser

fsi

sinon

si X=$ alors

si a=$ alors réponse=accepter

sinon réponse=refuser

fsi

Analyse Syntaxique

27

sinon

si X=a alors

dépiler(X)

avancer(ps)

sinon

réponse=refuser

fsi

fsi

fsi

jusqu'à (réponse=accepter) ou (réponse=refuser)

Fin

Exemple : Soient le mot m=3+4*5 et la grammaire représentée par les règles de production

suivantes :

E → TE’

E’ → +TE’ | ε

T → FT’

T’ → *FT’ | ε

F → (E) | nb

En appliquant l’algorithme précédent, on obtient les traces suivantes :

pile

$ E

$ E'T

$ E'T'F

$ E'T'3

$ E'T'

$ E'

$ E'T+

$ E'T

$ E'T'F

$ E'T'4

$ E'T'

$ E'T'F*

$ E'T'F

$ E'T'5

$ E'T'

$ E'

$

Entrée

3+4*5$

3+4*5$

3+4*5$

3+4*5$

+4*5$

+4*5$

+4*5$

4*5$

4*5$

4*5$

*5$

*5$

5$

5$

$

$

Sortie

E → TE’

T → FT’

F → nb

T’ → ε

E’ → +TE’

T → FT’

F → nb

T’ → *FT’

F → nb

T’ → ε

E’ → ε

$ Le mot est accepté

Analyse Syntaxique

28

On obtient donc l'arbre syntaxique de la figure Fig. 1.

Fig. 1 Arbre syntaxique associé au mot m = 3+4*5

2.1.5. Les Grammaires LL(1)

Définissons, d’abord, une grammaire LL(1).

Définition : Une grammaire LL(1) est une grammaire pour laquelle la table d'analyse LL(1) n'a

aucune case ayant des entrées multiples, i.e., plusieurs règles de production associées à la même

case.

Le terme "LL(1)" signifie que l'on parcourt le mot à analyser de gauche à droite (L pour Left to

right scanning), que l'on utilise les dérivations gauches (L pour Leftmost derivation), et qu'un seul

(1) symbole de prévision est nécessaire à chaque étape nécessitant la prise d'une décision d'action

d'analyse.

L'algorithme d’analyse syntaxique, présenté dans le paragraphe suivant, ne peut être appliqué

qu’aux grammaires LL(1). En effet, si la table d'analyse LL(1) comporte des cases auxquelles

plusieurs règles de production sont associées, on ne pourra pas savoir quelle est règle de production

appliquer. Si la grammaire n’est pas LL(1), il faut essayer de la rendre LL(1).

Exemple : Nous avons déjà vu la grammaire représentée par les règles de production

suivantes :

S → aAb

A → cd | c

Nous avons premier(S)={a}, premier(A)={c}, suivant(S)={$} et suivant(A)={b}, ce qui donne

la table d'analyse LL(1) suivante :

Analyse Syntaxique

29

a

c

b d $

S →

aAb

S

A

A → cd

A → c

Il y a deux réductions pour la case M[A,c], donc ce n'est pas une grammaire LL(1). On ne peut

pas utiliser cette méthode d'analyse. En effet, on l'a déjà remarqué, pour pouvoir choisir entre la

production A → cd et la production A → c, il faut lire la lettre qui suit celle que l'on pointe (donc

deux symboles de prévision sont nécessaires).

Définition : Une grammaire est immédiatement récursive à gauche si elle contient un non-

terminal A tel qu'il existe une production A → Aα, où α est une séquence de symboles quelconques.

Définition : Une grammaire est récursive à gauche si elle contient un non-terminal A tel qu'il

existe une dérivation A

Aα, où α est une séquence de symboles quelconques.

Théorème : Une grammaire récursive à gauche n'est pas LL(1).

Exemple : Soit la grammaire représentée par les règles de production suivantes :

S → Aa | b

A → Ac | Sd | ε

Cette grammaire n’est pas LL(1), puisque, le symbole non-terminal S est récursif à gauche. En

effet, on a S → Aa → Sda . Mais il n'est pas immédiatement récursif à gauche.

Exemple : Soit la grammaire représentée par les règles de production suivantes :

S → aTbbbb

T → Tb | ε

Cette grammaire n’est pas LL(1), puisque, le symbole non-terminal T est immédiatement

récursif à gauche. Donc, il est récursif.

Exemple : Cette grammaire contient des récursivités à gauche immédiates donc elle n’est pas

LL(1).

S → ScA | B

A → Aa | ε

B → Bb | d | ε

2.2. Analyse Ascendante

Définissons, d’abord, une analyse ascendante.

Définition : Une analyse ascendante construire consiste à construire l'AD du bas vers le haut.

Le haut étant la racine, i.e., l'axiome de la grammaire du langage. Le bas étant les feuilles, i.e., les

unités lexicales.

Une technique d’analyse ascendante consiste à suivre un processus de décalage-réduction. En

suivant ce processus, on ne peut réaliser que deux types opérations :

Analyse Syntaxique

30

(i) L’opération de décalage, en anglais shift : Décaler d'une lettre le pointeur sur le mot à

analyser

(ii) L’opération de réduction, en anglais reduce : Réduire une séquence de symboles

quelconques par un symbole non-terminal en utilisant une des règles de production.

Exemple : Soient grammaire représentée par la rège S → aSbS

le mot

m=aacbaacbcbcbcbacbc. Est-ce que m est un mot du langage défini par cette grammaire?

Répondons à cette question en faisant une analyse ascendante :

| c et

1.

on ne peut rien réduire, donc on décale

2.

on ne peut rien réduire, donc on décale

3.

on ne peut rien réduire, donc on décale

4.

on peut réduire par S → c

5.

on ne peut rien réduire, donc on décale

...

6.

on peut utiliser S → c

7.

on ne peut rien réduire, donc on décale

Analyse Syntaxique

31

8.

on ne peut rien réduire, donc on décale

9.

On peut utiliser S → c

10.

Publicité

On peut utiliser S → aSbS

11.

décalage

12.

décalage

13.

réduction par S → c

14.

réduction par S → aSbS

15.

réduction par S → aSbS

Analyse Syntaxique

32

16.

décalage

17.

décalage

18.

réduction par S → c

19.

réduction par S → aSbS

20.

décalage

21.

décalage

22.

décalage

23.

réduction par S → c

Analyse Syntaxique

33

24.

décalage

25.

décalage

26.

réduction par S → c

27.

réduction par S → aSbS

28.

réduction par S → aSbS

29.

Terminé : Le mot a été réduit à l’axiome de la grammaire. Donc, c’est un mot du langage.

Les opérations réalisées ci-dessus peuvent être résumées par l'arbre suivant :

Analyse Syntaxique

34

Fig. 2 Analyse ascendante du mot m=aacbaacbcbcbcbacbc

Le processus de décalage-réduction peut être réalisé en utilisant une table, appelée table

d'analyse LR. Cette table nous indique, pour chaque symbole de séquence de symboles courantes,

si on doit faire un décalage ou bien si on doit faire une réduction.

Dans ce cours, nous ne n’aborderons pas le problème de construction de cette table.

Définition : Une table d'analyse LR, notée M, associée à une grammaire G = (VT,VN,S,P), est

une table qui représente une espèce d'automate, appelé automate à pile. Cette table est définie

comme suit :

(i) Une ligne i représente l’état i de l’automate,

(ii) Une colonne a représente un élément de VTVN,

(iii) Une case M[i,a] est définie comme suit :

dj. Dans ce cas, on fait une opération de décalage : On empile le symbole a

dans une pile associée à l'automate et on passe de l’état i l’état j.

M[i,a] =

rp. Dans ce cas, on fait une opération de réduction : On remplace la

séquence de symboles en sommet de pile associée à l'automate, qui

correspond à la partie droite de la règle numéro p, par le symbole non-

terminal de la partie gauche de cette règle. Puis, on passe de l’état i

l’état j.

Exemple : Avec la grammaire des expressions arithmétiques, représentée par les règles de

production suivantes :

E → TE’

E’ → +TE’ | ε

T → FT’

T’ → *FT’ | ε

F → (E) | nb

Analyse Syntaxique

35

on obtient la table d'analyse LR suivante :

nb

d5

d5

d5

d5

0

1

2

3

4

5

6

7

8

9

10

11

+ *

(

d

)

$

E

T F

1

2

3

4

d

r

4

r

4

4

d

r

r

d

r

7

r

4

6

2

4

r

6

6

d

r

7

r

3

r

5

6

1

3

5

8

2

3

9

3

1

0

A

CC

r

r

r

r

2

4

2

4

d

r

r

6

6

d

d

d

r

r

r

11

1

3

5

r

r

r

1

3

5

Exemple : Faisons analyse ascendante du mot m = 3 + *4 en utilisant la table d'analyse LR

précédente.

Analyse Syntaxique

36

Fig. 3 Analyse LR du mot m = 3 + *4$

Exemple : Faisons analyse ascendante du mot m = 3+4*2 en utilisant la table d'analyse LR

précédente.

²²

Fig. 4 Analyse LR du mot m = 3+4*2

Analyse Syntaxique

37

Fig. 5 Arbre de dérivation du mot m = 3+4*2

*