Notes Theorie Des Langages
Notes Theorie Des Langages
Notes Theorie Des Langages
Alexis Nasr
Table des matières
1 Introduction 5
1.1 Le paysage syntaxique . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.1 Opérations sur les langages . . . . . . . . . . . . . . . . . . . 6
1.2 Grammaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.1 Hiérarchie des grammaires . . . . . . . . . . . . . . . . . . . 9
1.2.2 Type d’un langage . . . . . . . . . . . . . . . . . . . . . . . 10
1.3 Reconnaisseurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2 Langages réguliers 15
2.1 Expressions régulières . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.1 Manipulation d’expressions régulières . . . . . . . . . . . . . 16
2.2 Expressions régulières ⇔ grammaires régulières . . . . . . . . . . . 17
2.2.1 Expressions régulières ⇒ grammaires régulières . . . . . . . 18
2.2.2 Grammaires régulières ⇒ expressions régulières . . . . . . . 19
2.3 Automates finis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3.1 Automate complet . . . . . . . . . . . . . . . . . . . . . . . 22
2.3.2 Représentation graphique d’un automate fini . . . . . . . . . 22
2.3.3 Représentation tabulaire d’un automate fini . . . . . . . . . 23
2.3.4 Automates non déterministes . . . . . . . . . . . . . . . . . 23
2.3.5 Propriétés de fermeture . . . . . . . . . . . . . . . . . . . . . 27
2.3.6 Minimalisation . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.4 Expressions régulières ⇔ automates finis . . . . . . . . . . . . . . . 33
2.4.1 Expression régulière ⇒ automate . . . . . . . . . . . . . . . 33
2.4.2 Automate ⇒ expression régulière . . . . . . . . . . . . . . . 35
3
3.4.1 Grammaires hors-contexte ⇒ Automate à pile . . . . . . . . 50
3.5 Analyse syntaxique . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.5.1 Transducteurs à pile . . . . . . . . . . . . . . . . . . . . . . 52
3.5.2 Analyseurs gauches . . . . . . . . . . . . . . . . . . . . . . . 53
3.6 Analyse descendante . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.6.1 Analyseur récursif . . . . . . . . . . . . . . . . . . . . . . . . 55
3.6.2 Analyseur prédictif non récursif . . . . . . . . . . . . . . . . 57
Chapitre 1
Introduction
Les symboles sont des éléments indivisibles qui vont servir de briques de base pour
construire des mots. On peux citer comme exemple de symboles les 26 lettres de
l’alphabet romain a, b, c...z, les chiffres décimaux 0, 1, ...9.
Une suite de symboles, appartenant à un alphabet Σ, mis bout à bout est appelé
un mot (ou une chaı̂ne) sur Σ. 01001100, par exemple est un mot construit sur
l’alphabet B. Le nombre de symboles entrant dans la composition d’un mot α est
appelé la longueur de α, que l’on note à l’aide de deux barres verticales : |α|. La
longueur du mot 01001100, par exemple (notée |01001100|) vaut huit 1 .
Il est utile de pouvoir désigner un mot particulier, dont la longueur vaut zéro,
que l’on appellera le mot vide. Ce mot est conventionnellement représenté par le
symbole ε2 .
5
β = cadabra, αβ = abracadabra. Le mot mn représente la concaténation de m
avec lui même n fois :
n
z }| {
m . . . m = mn
Etant donné trois mots α, β et γ définis sur un alphabet Σ, on dit que α est un
préfixe du mot αβ β un suffixe du mot αβ et β une sous-chaı̂ne de αβγ. ε est un
préfixe, un suffixe et une sous-chaı̂ne de tout mot. Si α 6= β et α est un préfixe (ou
suffixe) de β, alors on dit que α est un préfixe (ou suffixe) propre de β.
L’ensemble de tous les mots que l’on peut construire sur un alphabet Σ, ε inclu,
est noté3 Σ∗ . On a donc en particulier :
L1 ∪ L2 = {x|x ∈ L1 ou x ∈ L2 }
L1 ∩ L2 = {x|x ∈ L1 et x ∈ L2 }
– La différence de L1 et L2 est le langage, noté L1 − L2 , constitué des mots ap-
partenant à L1 et n’appartenant pas à L2 .
L1 − L2 = {x|x ∈ L1 et x ∈
/ L2 }
– La différence de Σ∗ et de L, noté L̄ est appelé le complément du langage L :
L̄ = {x ∈ Σ∗ |x ∈
/ L}
On définit de plus l’opération de concaténation de deux langages : la concaténation
de deux langages L1 et L2 est le langage noté L1 L2 composé des mots xy tels que
x ∈ L1 et y ∈ L2 .
3
La définition de l’opérateur ∗ est donnée plus loin.
L1 L2 = {xy|x ∈ L1 ety ∈ L2 }
on note Ln la concaténation de L avec lui même n fois :
n
z }| {
L . . . L = Ln
On définit enfin la fermeture de Kleene du langage L, notée L∗ de la façon suivante :
[
L∗ = Lk
k≥0
1.2 Grammaires
Un langage étant défini comme un ensemble de mots, une première façon de décrire
un langage est d’énumérer tous les mots qui le constituent. Cette méthode se heurte
à une difficulté fondamentale qui est qu’elle ne permet pas de décrire les langages
composés d’un nombre infini de mots. De plus, même si le langage que l’on désire
décrire est fini, ce mode de description ne permet pas de mettre en évidence ce qui
est commun dans la structure des mots de ce langages. C’est la raison pour laquelle
on introduit la notion de grammaire comme méthode de définition d’un langage.
Une grammaire est un système mathématique qui permet de générer tous les mots
d’un langage, c’est la raison pour laquelle elles sont aussi appelées des grammaires
génératives . Etant donné une grammaire G, on notera L(G) le langage généré par
G. De plus, une grammaire permet d’attribuer aux mots appartenant au langage
qu’elle définit, une structure, appelée structure syntaxique des mots.
Une grammaire générative utilise deux alphabets. Un alphabet non terminal, que
l’on notera N, composé de symboles non terminaux et un alphabet terminal , noté
Σ, composé de de symboles terminaux . L’alphabet terminal est l’alphabet sur le-
quel sont construits les mots du langage défini par la grammaire. Les symboles
non terminaux sont utilisés dans le processus de génération.
Le cœur d’une grammaire est constitué de règles de production appelées aussi règles
de réécriture qui décrivent la façon de générer les mots du langage. Une règle de
production est en fait un couple de mots (α, β) composés de symboles terminaux
et non terminaux (α, β ∈ (V ∪ N)∗ ). Ce couple est noté conventionnellement à
l’aide d’une flèche : α → β. α est appelée la partie gauche de la règle α → β et
β sa partie droite. α n’est pas un mot quelconque, il doit contenir au moins un
symbole non terminal.
α → β1 |β2 | . . . |βn
les n règles :
α → β1 , α → β2 , . . . , α → βn
Ce qu’une règle α → β dit c’est que α peut se réécrire β. Si l’on dispose d’un
mot x que l’on a réussi à générer et que α est une sous-chaı̂ne de x, alors on peut
générer un nouveau mot en remplaçant α par β. Ce mécanisme est décrit plus
précisément ci-après.
4
– P est un sous ensemble fini de :
un élément (α, β) de P , que l’on note α → β est appelé une règle de production
ou règle de réécriture.
αβγ ⇒ αδγ
k
On notera α ⇒ β pour indiquer que β se dérive de α en k étapes.
+ ∗
On définit aussi les deux notations ⇒ et ⇒ de la façon suivante :
4
(N ∪ Σ)∗ N (N ∪ Σ)∗ est le langage issu de la concaténation des trois langages (N ∪ Σ)∗ , N
et (N ∪ Σ)∗ . Ce dernier est la fermeture de Kleene du langage (N ∪ Σ) qui est lui même l’union
des deux langages M et Σ.
+ k
– α ⇒ β ≡ α ⇒ β avec k > 0
∗ k
– α ⇒ β ≡ α ⇒ β avec k ≥ 0
En utilisant ces notations, l’ensemble des mots générés par la grammaire G (en
d’autres termes le langage L(G)) est défini de la façon suivante :
∗
L(G) = {m ∈ Σ∗ |S ⇒ m}
Deux grammaires G et G′ sont équivalentes si les langages L(G) et L(G′ ) sont
identiques.
– règles hors-contexte :
Une règle A → α est un règle hors-contexte si et seulement si : A ∈ N et
α ∈ (N ∪ Σ)∗
– règles contextuelles :
Une règle α → β est une règle contextuelle si et seulement si : α = gAd et
β = gBd avec g, d, B ∈ (N ∪ Σ)∗ et A ∈ N le nom “contextuelle” provient du
fait que A se réecrit B uniquement dans le contexte g d.
– règles sans restrictions Une règle α → β est une règle sans restriction si et seule-
ment si : |α| ≥ 1
Il est important de remarquer que les types de règles définis ci-dessus définissent
une hiérarchie dans le sens où une règle régulière est un cas particulier de règle hors-
contexte qui est elle même un cas particulier de règle indépendante du contexte
et, pour finir, cette dernière est un cas particulier de règle non contrainte.
– hors contexte (ou grammaire de type 2) si toutes ses règles de production sont
hors contexte.
Les types de grammaires définis ci-dessus forment aussi une hiérarchie appelée
hiérarchie de Chomsky, représentée dans la figure 1.1.
grammaires contextuelles
grammaires hors-contexte
grammaires régulières
Il existe des langages “fondamentaux” pour les types de langages les plus utilisés,
ce sont des langages qui illustrent une propriété importante de leur classe :
– langages réguliers (de type 3)
le langage an , avec n ≥ 0 (les mots de longueur quelconque composés uniquement
de a), il peut être généré par la grammaire suivante : h{S}, {a}, {S → aS|ε}, Si.
langage mirroir, le langage des mots de la forme mm avec m ∈ Σ∗ : h{S}, {a, b}, {S →
aSa|bSb|aa|bb}, Si.
1.3 Reconnaisseurs
Les reconnaisseurs constituent une autre manière de décrire des langages. Un re-
connaisseur est en fait la description d’une machine abstraite qui prend en entrée
un mot et dit si ce mot appartient ou pas au langage décrit par la machine.
2. une tête de lecture, qui peut lire une case à un instant donné. La case sur
laquelle se trouve la tête de lecture à un moment donné s’appelle la case
courante. La tête peut être déplacée par le reconnaisseur pour se positionner
sur la case immédiatement à gauche ou à droite de la case courante.
3. une mémoire, qui peut prendre des formes différentes. La mémoire permet
de stocker des éléments d’un alphabet de mémoire.
4. une unité de contrôle, qui constitue le cœur d’un reconnaisseur. Elle peut
être vue comme un progamme qui dicte au reconnaisseur son comportement.
Elle est représentée par un ensemble fini d’états ainsi que par une fonction de
transition qui décrit le passage d’un état à un autre en fonction du contenu
de la case courante de la bande de lecture et du contenu de la mémoire.
L’unité de contrôle décide aussi de la direction dans laquelle déplacer la tête
de lecture et choisit quels symboles stocker dans la mémoire. Parmi les états
d’un reconnaisseur, on distingue des états initiaux, qui sont les états dans
lesquels doit se trouver le reconnaisseur avant de commencer à reconnaı̂tre
un mot et des états d’acceptation qui sont les états dans lequel doit se trouver
le reconnaisseur après avoir reconnu un mot.
L’état d’un reconnaisseur à un moment donné est décrit par sa configuration qui
se compose de trois informations :
1. L’état de l’unité de contrôle
BANDE DE LECTURE
TETE DE LECTURE
UNITE DE CONTROLE
MEMOIRE
AUXILIAIRE
Lors d’un mouvement, le reconnaisseur lit le symbole se trouvant dans la case cou-
rante, stocke de l’information dans sa mémoire et change d’état.
Une configuration d’acceptation est une configuration pour laquelle l’unité de contrôle
se trouve dans un état d’acceptation, la tête de lecture se trouve sur la case la plus
à droite et la mémoire se trouve dans un état d’acceptation.
On dit qu’un reconnaisseur accepte un mot m si, ayant m sur sa bande de lecture, le
reconnaisseur peut effectuer une séquence de mouvements l’amenant de la configu-
ration initiale à une configuration finale. Si le reconnaisseur est non déterministe,
il peut exister plusieurs séquences de mouvements vérifiant ces conditions.
Le langage reconnu par un reconnaisseur est l’ensemble des mots qu’il accepte.
Pour toute classe de grammaire dans la hiérarchie de Chomsky, il existe une classe
de reconnaisseurs qui définit la même classe de langages. En particulier, les auto-
mates finis dont il sera question au chapitre 2 définissent les langages réguliers et les
automates à pile, que l’on verra au chapitre 3 définissent les langages hors-contexte.
Chapitre 2
Langages réguliers
Nous allons maintenant introduire une notation pratique pour dénoter des en-
sembles réguliers sur Σ, que l’on appelle expression régulière sur Σ :
1. ∅ est une expression régulière dénotant l’ensemble régulier ∅.
2. ε est une expression régulière dénotant l’ensemble régulier {ε}.
3. a (tel que a ∈ Σ) est une expression régulière dénotant l’ensemble régulier
{a}.
4. Si p et q sont des expressions régulières dénotant respectivement les ensembles
réguliers P et Q alors :
(a) (p + q) est une expression régulière dénotant l’ensemble régulier P ∪ Q
(b) (pq) est une expression régulière dénotant l’ensemble régulier P Q
1
On pourra remarquer que tout langage fini est un ensemble régulier.
15
(c) (p)∗ est une expression régulière dénotant l’ensemble régulier P ∗
5. rien d’autre n’est une expression régulière.
Cette définition des expressions régulières peut sembler circulaire car on définit
les expressions régulières en fonction d’elle-mêmes, en particulier dans les cas 4, 5
et 6. Elle ne l’est en fait pas car on définit des expressions régulières en fonction
d’expressions régulières plus courtes : p et q sont plus courtes que p + q et pq et
p est plus courte que p∗ . On peut ainsi décomposer une expression régulière en
expressions régulières plus simples jusqu’à aboutir aux expressions élémentaires
des cas 1, 2 et 3.
0∗ 10∗ = {m ∈ Σ∗ | m a exactemement un 1}
(0 + 1)∗ 1(0 + 1)∗ = {m ∈ Σ∗ | m a au moins un 1}
(0 + 1)∗ 001(0 + 1)∗ = {m ∈ Σ∗ | m contient la sous-chaı̂ne 001}
((0 + 1)(0 + 1))∗ = {m ∈ Σ∗ | |m| est pair}
Il est clair d’après la définition des expressions régulières que l’on peut construire
une expression régulière dénotant un ensemble régulier quelconque. De même, on
peut construire l’ensemble régulier dénoté par toute expression régulière. Malheu-
reusement, pour tout ensemble régulier, il existe une infinité d’expression régulières
le dénotant.
α + (β + γ) = (α + β) + γ (2.1)
α+β = β+α (2.2)
α+∅ = α (2.3)
α+α = α (2.4)
α(βγ) = (αβ)γ (2.5)
εα = αε = α (2.6)
α(β + γ) = αβ + αγ (2.7)
(α + β)γ = αγ + βγ (2.8)
∅α = α∅ = α (2.9)
ε + αα∗ = α∗ (2.10)
ε + α∗ α = α∗ (2.11)
Ces différentes lois peuvent être prouvées en remplaçant chaque expression régulière
par la définition de l’ensemble qu’elle dénote et en raisonnant sur ces ensembles.
Voici quelques équivalence utiles que l’on peut dériver à partir ces lois :
a∗ a∗ = a∗
a∗∗ = a∗
(a∗ b)∗ a∗ = (a + b)∗
a(ba)∗ = (ab)∗ a
a∗ = (aa)∗ + a(aa)∗
Il est aussi possible de définir des équations régulières dont les variables et les
coefficients sont des ensembles réguliers. On peut par exemple écrire l’équation :
X = αX + β
où α et β sont des expressions régulières. On peut vérifier que X = α∗ β est une
solution de cette équation :
Les expressions régulières sur Σ permettent donc de dénoter exactement les lan-
gages qui peuvent être générés par une grammaire régulière. Nous disposons ainsi
de deux moyens équivalents pour décrire les langages réguliers : les grammaires
régulières et les expressions régulières. Nous allons démontrer ce théorème en
décrivant d’une part comment construire une grammaire régulière à partir d’une
expression régulière et inversement comment construire une expression régulière
dénotant le même langage qu’un grammaire régulière.
G = h{S}, Σ, ∅, Si
2. R = ε. R dénote le langage {ε} qui est aussi le langage généré par la gram-
maire régulière suivante :
G = h{S}, Σ, {S → ε}, Si
G = h{S}, Σ, {S → a}, Si
G = hN1 ∪ N2 , Σ, P, S1 i
où P est défini de la façon suivante :
– Si A → xB ∈ P1 alors A → xB ∈ P
– Si A → x ∈ P1 alors A → xS2 ∈ P
– Si p ∈ P2 alors p ∈ P
Il faut encore montrer que L(G) = L(G1 )L(G2 ) !
6. Si L1 est un langage régulier, généré par la grammaire G1 alors L∗1 est généré
par la grammaire :
G = hN1 ∪ {S}, Σ, P, Si
où S est un nouveau symbole non terminal tel que S ∈
/ N1 . P est défini de
la façon suivante :
– Si A → xB ∈ P1 alors A → xB ∈ P
– Si A → x ∈ P1 alors A → xS ∈ P
– S → S1 |ε ∈ P
Il faut encore montrer que L(G) = L(G1 )∗ !
Exemple : Construisons une grammaire équivalente à l’expression régulière R =
(a + b)∗ aba. Pour cela, on commence par décomposer R en sous expressions plus
simples jusqu’à aboutir aux expressions élémentaires a et b , pour lesquelles on
construit des grammaires suivantes2 :
a : {S1 → a}
b : {S2 → b}
On combine ensuite ces grammaires selon les règles 4, 5, et 6 pour construire les
grammaires correspondant aux expressions plus complexes :
S5 = aba (2.19)
Des équations 2.13, 2.14 et 2.15, on peut déduire :
δ :Q×Σ→ Q
Une configuration d’un automate fini est un couple (q, m) ∈ Q × Σ∗ . Etant donné
un automate fini et un mot m ∈ Σ∗ , une configuration de la forme (q0 , m) est
appelée configuration initiale et toute configuration de la forme (q, ε) avec q ∈ F
est une configuration d’acceptation.
Un état q de A est dit accessible s’il est possible d’y accéder depuis l’état initial
ou, plus précisément, s’il existe un mot m ∈ Σ∗ permettant d’effectuer une suite
de mouvements menant de l’état initial à q :
∗
q accessible ⇔ ∃m ∈ Σ∗ (q0 , m) ⊢ (q, ε)
il est dit co-accessible s’il est possible d’accéder à un état d’acceptation depuis cet
état, ou encore, s’il existe un mot m ∈ Σ∗ permettant d’effectuer une suite de
mouvements menant de q à un état d’acceptation :
∗
q co-accessible ⇔ ∃m ∈ Σ∗ (q, m) ⊢ (e, ε) avec e ∈ F
3
La fonction δ n’est pas forcément définie pour tous les couples de Q × Σ. Lorsqu’elle n’est
pas définie pour un couple (q, a), on note δ(q, a) = ∅.
Un mot m est reconnu par l’automate s’il existe une suite de mouvements menant
de la configuration (q0 , m) à (q, ε) avec q ∈ F . Le langage reconnu par un automate
A, noté L(A), est l’ensemble des mots reconnus par ce dernier4 :
∗
L(A) = {m ∈ Σ∗ |(q0 , m) ⊢ (q, ε) avec q ∈ F }
On dira qu’un langage L sur Σ est reconnaissable s’il existe au moins un automate
fini A ayant Σ comme alphabet d’entrée tel que L = L(A).
Un mot m est reconnu par un automate s’il existe un chemin dans le graphe, par-
tant de l’état initial et aboutissant à un état d’acceptation tel que la concaténation
des symboles étiquetant les arcs du chemin est égale à m. Le mot 0100 est donc
reconnu par l’automate car il correspond au chemin ABABB.
Un état q est accessible s’il existe un chemin menant de l’état de départ à q ; il est
co-accessible s’il existe un chemin menant de q à un état d’acceptation.
4
On remarquera qu’un état non accessible ou non co-accessible est inutile du point de vue du
langage reconnu par l’automate.
1 0
A B
0 1
→ A B A
← B B A
Fig. 2.2 – Représentation tabulaire d’un automate
La définition formelle d’un automate fini non déterministe se distingue de celle d’un
automate déterministe par la fonction de transition. Dans le cas d’un automate
déterministe, la fonction de transition associe un état à un couple composé d’un
état et d’un symbole (δ : Q×Σ → Q) alors que pour un automate non déterministe,
cette fonction associe un ensemble d’états à un couple composé d’un état et d’un
symbole ou d’un état et du mot vide. L’automate peut donc d’une part transiter à
partir d’un état q et sur un symbole a vers plusieurs états et d’autre part change
d’état sans lire de symbole dans le mot à reconnaı̂tre. La fonction de transistion
est par conséquent définie de la façon suivante :
δ : Q × Σε → ℘(Q)
où Σε = Σ ∪ {ε} et ℘(Q) est l’ensemble des parties de Q. Une transition associant
un ensemble d’état au couple (q, ε) est appelée une transition-ε.
Le déterminisme se traduit dans la représentation graphique d’un automate fini
par le fait qu’il ne peut y avoir plus d’un arc possédant la même étiquette émanant
d’un même état. Lorsque l’automate est non déterministe, une telle configuration
peut exister, comme dans la figure 2.3. De plus, un arc peut être étiqueté par le
mot vide ε. Un tel arc peut être traversé sans qu’un symbole du mot d’entrée
soit lu. Dans la représentation tabulaire, le non déterminisme est illustré par la
présence de plusieurs états dans une case du tableau et d’une colonne réservées
aux transitions-ε.
1,0
0
A B
La reconnaissance d’un mot par un automate non déterministe est un peu plus
délicate que dans le cas déterministe. Il est possible, du fait du non-déterminisme
de l’automate qu’à un moment donné de la reconnaissance, alors que l’automate se
trouve dans une configuration donnée, il existe plusieurs états vers lesquels tran-
siter. Il faut alors dédoubler le processus de lecture de façon à poursuivre tous
les chemins possibles en parallèle. Chaque “copie” du processus va poursuivre un
chemin. Si un processus est confronté à un nouveau choix alors il se dédouble à
nouveau, et ainsi de suite. Si un processus se trouve dans une configuration telle
qu’il ne peut effectuer aucune transition, alors il meurt. Finalement, si un de ces
processus atteint un état d’acceptation après avoir lu le dernier symbole du mot à
reconnaı̂tre alors tous les processus s’arrêtent et le mot est reconnu par l’automate.
La reconnaissance du mot ababab par cet automate est représentée dans la fi-
gure 2.4.
Partant de la configuration (0, ababab), l’automate effectue en parallèle deux mou-
vements qui le mènent vers les configurations (0, babab) et (1, babab). Cette dernière
permet un mouvement vers (2, abab) qui elle ne permet aucun mouvement, ce pro-
cessus s’arrête donc. La configuration (0, babab) mène à (0, abab) de laquelle deux
mouvements vers (1, bab) et (0, bab) sont possibles . . .
(0, ababab)
HH
HH
H
(0, babab) (1, babab)
(2, ε) (0, ε)
Fig. 2.4 – Reconnaissance non déterministe
Tout ceci est décrit plus formellement ci-dessous. Nous procèderons en deux étapes.
Lors d’une première étape, nous éliminerons de N les éventuelles transitions-ε et
dans une seconde étape, nous réduirons les transitions d’un même état sur un
même symbole.
a
a
a
a b
→ 0 {0, 1} 0
1 2 2
← 2 ∅ ∅
a b
→ 0 01 0
un nouvel état 01 a été crée, dont on calcule les transition. Ce calcul mène à la
création des deux nouveaux états 01 et 012 qui ne donneront pas naissance à de
nouveaux états, ce qui nous donne l’automate déterministe suivant :
a b
→ 0 01 0
01 012 02
← 02 01 0
← 012 012 02
A1UA2
A1
A2
ε
Concaténation
On construit l’automate A tel que L(A) = L(A1 )L(A2 ). L’idée est d’ajouter aux
états d’acceptation de A1 des transitions-ε vers l’état initial de A2 . Ainsi un mot
est reconnu par A s’il peut être décomposé en un mot reconnu par A1 suivi d’un
mot reconnu par A2 . Là aussi, A est non déterministe. Cette construction est
représentée graphiquement dans la figure 2.8.
Plus formellement :
A1A2
Etoile
On construit l’automate A tel que L(A) = L(A1 )∗ . Les mots acceptés par A
peuvent être décomposés en plusieurs mots dont chacun peut être reconnu par
A1 . L’idée est d’ajouter aux états d’acceptation de A1 des transitions-ε vers l’état
initial de A1 . Ainsi, lors de la reconnaissance d’un mot m par A, lorsqu’un préfixe
de m appartenant à L(A1 ) a été reconnu et que l’on se trouve par conséquent
dans un état d’acceptation de A1 , la transition-ε peut être empruntée pour re-
connaı̂tre une nouvelle occurrence d’un mot de L(A1 ). De plus A doit accepter le
mot vide, pour cela on crée un nouvel état initial qui est aussi un état d’accepta-
tion et qui possède une transition-ε vers l’état initial de A1 6 . Cette construction
est représentée graphiquement dans la figure 2.9.
A A∗
ε
Formellement :
Complémentation
On construit l’automate A tel que L(A) = Σ∗ − L(A1 ). L’idée est de partir d’un
automate déterministe complet et d’échanger les états d’acceptation en états de
non acceptation. Ainsi un mot qui était reconnu par A1 ne sera pas reconnu par
le nouvel automate et un mot qui n’était pas reconnu par A1 le sera.
Formellement : A = hQ, Σ, δ, q0 , Q − F i
Intersection
La fermeture des langages reconnaissables pour l’intersection peut être déduite de
la fermeture pour l’union et la complémentation grâce aux lois de de Morgan :
L3 = L1 ∩ L2 ⇔ L3 = L1 ∪ L2
Pour construire A tel que L(A) = L(A1 ) ∩ L(A2 ), il suffit donc de déterminiser et
compléter A1 et A2 , de construire leurs complémentaires puis de construire l’union
des complémentaire que l’on déterminisera et complètera avant d’en construire le
complémentaire. C’est un peu long !
On peut aussi définir directement A en construisant des états qui sont en fait des
couples d’états (q1 , q2 ) avec q1 ∈ A1 et q2 ∈ A2 . Un tel état indique que l’on par-
cours “en même temps” A1 et A2 . On établit une transition entre (q1 , q2 ) et (q1′ , q2′ )
sur a s’il existe une transition sur a entre q1 et q1′ et entre q2 et q2′ .
Plus formellement :
2.3.6 Minimalisation
Un automate fini déterministe est minimal si tout autre automate fini déterministe
reconnaissant le même langage comporte au moins autant d’états.
L’unicité de l’automate minimal est une propriété importante car elle permet de
vérifier que deux automates reconnaissent le même langage. En effet, si l’on dispose
de deux automates déterministe, il suffit de construire les automates minimaux leur
correspondant. Si ces derniers sont égaux (au nom des états près) alors les deux
automates initiaux reconnaissent bien le même langage.
– les états non co-accessibles (comme l’état puits) sont toujours séparés des autres
états.
Le principe de construction de l’automate minimal (Algorithme de Moore) revient
à regrouper au sein d’un même état les états qui ne sont séparés par aucun mot ;
deux état de l’automate initial seront donc dans des états différents de l’automate
minimal s’il existe un mot qui les sépare. Ceci revient à réaliser une partition de
l’ensemble des états de l’automate initial.
Illustrons cela sur l’automate déterministe suivant qui reconnaı̂t le langage L((a +
b)∗ abb) :
a b
→ A B C
B B D
C B C
D B E
← E B C
La partition initiale Π consiste en deux groupes (E), l’état d’acceptation et (A, B, C, D),
les états de non-acceptation. Pour construire Πn , on considère d’abord le groupe
(E). Ce groupe étant composé d’un seul état, il ne peut être décomposé et (E)
est placé dans Πn . On considère ensuite le groupe (A, B, C, D). Sur le symbole
a, chacun de ses états a une transition vers B, ils ne sont donc pas séparés par
a. Par contre, sur le symbole b, A, B et C ont une transition vers des membres
de (A, B, C, D) tandis que D a une transition vers E, ainsi, dans Πn (A, B, C, D)
doit être séparé en deux groupes : (A, B, C) et (D) ; Πn est donc (A, B, C)(D)(E).
A la seconde itération, (A, B, C) n’est toujours pas séparé par a par contre il est
séparé par b en (A, C) et (B). La nouvelle partition est donc (A, C)(B)(D)(E).
Une nouvelle itération ne parviendra pas à diviser (A, C), (A, C)(B)(D)(E) est
donc la partition finale. Si l’on choisit A comme représentant de (A, C), on obtient
le tableau suivant :
a b
→ A B A
B B D
D B E
← E B A
Nous allons prouver le théorème de Kleene en proposant une méthode pour constuire
un automate fini à partir d’une expression régulière ainsi qu’une méthode permet-
tant de construire une expression régulière à partir d’un automate fini.
2. E = ε. E dénote le langage {ε} qui est aussi le langage reconnu par l’auto-
mate suivant :A = h{q1 }, Σ, δ, q1 , {q1 }i avec δ(r, b) = ∅, ∀r, ∀b.
4. E = E1 + E2
5. E = E1 E2
6. E = E1∗
a
ε
a+b :
ε b
ε
a
ε
(a+b)* : ε
ε b
aba : a ε b ε a
ε
a
ε
ε
(a+b)*aba :
ε b ε
ε
ε ε
ε b ε a
a
Un automate généralisé n’est rien d’autre qu’un automate fini dont les transitions
sont étiquetées par des expressions régulières et non pas simplement des symboles
ou le mot vide. L’automate généralisé lit le mot à reconnaı̂tre par blocs de symboles.
Les automates généralisés que nous allons manipuler vérifient trois contraintes
supplémentaires :
– L’état initial possède des transitions vers tous les autres états, mais aucun état
n’a de transition vers l’état initial.
– Il n’y a qu’un état d’acceptation qui ne possède aucune transition vers d’autres
états, mais tous les autres états possèdent une transition vers l’état d’accepta-
tion. De plus, l’état d’acceptation est distinct de l’état initial.
– A l’exception de l’état d’acceptation et de l’état initial, tous les états possèdent
une transition et une seule vers tous les autres états.
Un exemple d’automate généralisé est représenté dans la figure 2.11
aa
ab*
a* ab+ba
(aa)*
b*
b
ab
0
ε ε
I A B F
R1 R2∗ R3 + R4
où R4 est l’étiquette de la transition qui existait dans G entre q1 et q2 . Cette
élimination d’état est représentée dans la figure 2.13.
R2
R1 R3
q1 q2 q3
R4
R1 R*
2 3R 4+ R
q1 q3
1*0 ε
I A F
1*0(0+11*0)*
I F
39
3.1.2 Arbre de dérivation
Etant donné une grammaire hors-contexte G, nous avons vu ci-dessus qu’il est pos-
sible d’avoir plusieurs dérivations équivalentes d’un mot m qui ne se distinguent
que par l’ordre dans lequel ont été appliquées les règles de réécriture. On peut
représenter toutes ces dérivations sous la forme d’un arbre de dérivation, défini
ci-dessous.
Un arbre de dérivation indique les règles qui ont été utilisées dans une dérivation,
mais pas l’ordre dans lequel elles ont été utilisées.
F T
HH
a F * T
a F
a
On pourra remarquer qu’à un arbre de dérivation correspondent une seule dérivation
droite et une seule dérivation gauche. Dans le cas de l’arbre ci-dessus, ces deux
dérivations sont représentées en 3.1.1.
3.1.3 Ambiguı̈té
Si une grammaire G permet d’attribuer plus d’un arbre de dérivation à un mot
m ∈ L(G), elle est dite ambiguë. La grammaire
E E
HH
HH H
HH H
E + E E * E
HH H
H
a E * E E + E a
a a a a
On pourra remarquer que les langages générés par G1 et G2 sont identiques3 .
Cependant, certains langages hors-contextes ne peuvent être générés que par des
grammaires ambiguës. Ces langages sont dits intrinsèquement ambigus.
L’ambiguı̈té est une propriété gênante pour certaines grammaires, telles que les
grammaires des langages de programmation car elles permettent de donner plu-
sieurs interprétations différentes d’un même programme.
+
X ∈ N inaccessible ⇔ {m = αXβ , α, β ∈ (Σ ∪ N)∗ | S ⇒ m} = ∅
– Une règle de la forme A → B est dite règle simple . Toute grammaire compor-
tant des règles simples peut être transformée en une grammaire équivalente ne
3
On dit que G1 et G2 on le même pouvoir génératif faible (elles génèrent les mêmes langages)
mais des pouvoirs génératifs fort différents (elles n’associent pas la même structure aux mots du
langage).
comportant pas de telles règles.
+
– Une grammaire G est sans cycle si n’existe pas de dérivation de la forme A ⇒
A , ∀A ∈ N
– Une grammaire G est propre si elle est sans cycle, sans règles-ε et ne possède
pas de symboles inutiles. Tout langage hors contexte peut être généré par une
grammaire propre.
A → BC ou A → a
avec A, B ∈ N et a ∈ Σ. De plus, on autorise la règle S → ε si S est l’axiome de
la grammaire et s’il n’apparaı̂t jamais dans la partie droite d’une règle.
Tout langage hors-contexte peut être généré par une grammaire hors-contexte en
forme normale de Chomsky.
Pour prouver ce résultat, il suffit de montrer que l’on peut constuire pour toute
grammaire hors-contexte une grammaire équivalente en forme normale de Chom-
sky. Il n’est pas nécessaire de montrer l’inverse puisque toute grammaire en forme
normale de Chomsky est une grammaire hors-contexte.
Exemple :
S0 → S S0 → ASA|aB|a|SA|AS
S → ASA|aB|a|SA|AS S → ASA|aB|a|SA|AS
A → B|S A → B|S
B→b B→b
Elimination de A → B à gauche et de A → S à droite :
S0 → ASA|aB|a|SA|AS S0 → ASA|aB|a|SA|AS
S → ASA|aB|a|SA|AS S → ASA|aB|a|SA|AS
A → S|b A → b|ASA|aB|a|SA|AS
B→b B→b
4. Transformation des règles restantes.
S0 → AA1 |UB|a|SA|AS
S → AA1 |UB|a|SA|AS
A → b|AA1 |UB|a|SA|AS
A1 → SA
U →A
B→b
3.2.2 Grammaires non récursives à gauche
Un symbole non terminal A d’une grammaire G = hN, Σ, P, Si est dit récursif si
∗
A ⇒ αAβ avec α, β ∈ (N ∪ Σ)∗ . Si α = ε, A est dit récursif à gauche . Si β = ε, A
est dit récursif à droite . Une grammaire comportant au moins un symbole réursif
à gauche (resp. droite) est dite grammaire récursive à gauche (resp droite).
Tout langage hors-contexte peut être généré par une grammaire hors-contexte
non récursive à gauche.
Comme nous l’avons fait pour la forme normale de Chomsky, nous allons mon-
trer ce résultat, en présentant une méthode de transformation d’une grammaire
hors-contexte quelconque en une grammaire équivalente non récursive à gauche.
Nous procèderons en deux étapes, lors d’une première étape nous montrerons com-
ment éliminer la récursivité gauche directe puis dans une seconde étape comment
éliminer la récursivité gauche indirecte.
G′ = hN ∪ {A′ }, Σ, P ′ , Si
où P ′ est égale à P avec les règles ayant A pour partie gauche remplacées par :
A → β1 | β2 | . . . | βn | β1 A′ | β2 A′ | . . . | βn A′
A′ → α1 | α2 | . . . | αm | α1 A′ | α2 A′ | . . . | αm A′
Exemple : Cette transformation appliquée aux règles suivantes :
E → E + T | T , T → T ∗ F | F , F → (E) | a
produit les règles :
E → T | T E ′ , E ′ → +T | + T E ′ , T → F | F T ′ , T ′ → ∗F | ∗ F T ′, F → (E) | a
Méthode :
– Numéroter les non terminaux de G : N = {A1 , . . . , An }
– éliminer les récursivités à gauche directes des règles ayant A1 pour partie gauche.
– Pour i = 2 à n faire
– pour j = 1 à i − 1 faire
1. remplacer chaque règle de la forme Ai → Aj γ par les règles Ai →
δ1 γ | . . . | δk γ, où Aj → δ1 | . . . | δk sont toutes les règles ayant Aj
pour partie gauche.
2. éliminer les récursivités à gauche directes des règles ayant Ai pour partie
gauche.
La raison pour laquelle l’algorithme ci-dessus produit l’effet voulu est qu’après la
(i − 1)ème itération de la boucle la plus externe (en i), chaque règle de la forme
Aj → Al α, où j < i doit être telle que l > j. Il en résulte qu’à l’itération suivante
dans la boucle interne (en j), les remplacements successifs de Aj dans les règles de
la forme Ai → Aj α va avoir pour conséquence que les règles de la forme Ai → Al α
seront telles que l ≥ i et l’élimination de la récursivité directe sur Ai va faire que
l > i.
Exemple :
A → BC | a, B → CA | Ab, C → AB | CC | a
Posons A1 = A, A2 = B et A3 = C.
Méthode : Pour chaque symbole non terminal A, trouver le plus long préfixe α 6= ε
commun à deux règles ou plus ayant A pour partie gauche. Remplacer toutes les
règles ayant A pour partie gauche :
A → αA′ | γ
A′ → β1 | β2 | . . . | βn
Exemple : G = h{E, S}, {i, t, e, a, b}, {S → iEtS | iEtSeS | a, E → b}, Si
Factorisée à gauche, cette grammaire devient :
G = h{E, S, E ′ }, {i, t, e, a, b}, {S → iEtSS ′ | a, S ′ → eS | ε, E → b}, Si
BANDE DE LECTURE
car il peut “mémoriser” le nombre de a qu’il a lu (en les mettant dans la pile),
et par conséquent vérifier que le mot à reconnaı̂tre comporte le même nombre de b.
Les automates à pile peuvent être non déterministes. Contrairement aux langages
réguliers, certains langages hors-contexte ne peuvent être reconnus que par des
automates non déterministes.
δ : Q × (Σ ∪ {ε}) × Γ → ℘(Q × Γ∗ )
Une configuration d’un automate à pile est défini par un triplet (q, m, α) ∈ Q ×
Σ∗ × Γ∗ où :
– q représente l’état courant de l’unité de contrôle
– m est la partie du mot à reconnaı̂tre non encore lue. Le premier symbole de m
(le plus à gauche) est celui qui se trouve sous la tête de lecture. Si m = ε alors
tout le mot a été lu.
– α représente le contenu de la pile. Le symbole le plus à gauche est le sommet de
la pile. Si α = ε alors la pile est vide.
La fonction de transition d’un automate à pile permet de décrire le passage d’une
configuration de l’automate à une autre. On écrit :
a, a −> aa b, a −> ε
q0 q1 q2
a, Z −>aZ b, a −> ε
b , a ε
C D c ,$ $
ε, ε ε ε, ε ε
ε, ε ε ε, ε ε
B E F c , a ε
a ,ε a b ,ε ε
Une configuration d’acceptation est une configuration de la forme (q, ε, Z0) avec
q ∈ F . En d’autres termes, A se trouve dans un état d’acceptation, le mot à re-
connaı̂tre a été lu en entier et la pile ne contient que le symbole de fond de pile.
Un mot m ∈ Σ∗ est accepté par A s’il existe une séquence de mouvements de l’au-
tomate menant d’une configuration initiale (q0 , m, Z0 ) à une configuration d’accep-
tation (q, ε, Z0) avec q ∈ F . Le langage reconnu par A, noté L(A) est l’ensemble
des mots reconnus par A :
∗
L(A) = {m ∈ Σ∗ | (q0 , m, Z0 ) ⊢ (q, ε, Z0)}
L’automate A1 reconnaı̂t le mot aabb en effectuant les mouvements suivants :
(q0 , aabb, Z) ⊢ (q1 , abb, aZ) ⊢ (q1 , bb, aaZ) ⊢ (q2 , b, aZ) ⊢ (q2 , ε, Z)
Lorsque l’automate est non-déterministe, certaines configurations autorisent plus
d’un mouvement, comme l’illustre ci-dessous les différentes séquences de mouve-
ments de l’automate A2 lors de la reconnaissance du mot aabcc.
(B, aabcc, $)
(F, ε, $)
L’idée clef est d’écrire dans la pile de A les proto-phrases qui constituent la
dérivation recherchée. Pour cela, on commence par empiler l’axiome S, puis on
le remplace par la partie droite d’une règle de P de la forme S→ α de telle sorte
que le premier symbole x de α se trouve en sommet de pile.
– Si x est un terminal alors on le compare avec le caractère se trouvant sous la
tête de lecture. S’ils sont égaux alors on dépile.
– Si x est un non terminal alors on le remplace par la partie droite d’une règle de
P de la forme x → β.
Les différents états de la pile de l’automate correspondant à la grammaire G1 lors
de la reconnaissance du mot a + a ∗ a sont représentés dans la figure 3.4. On re-
marquera que la dérivation qui est construite lors de la reconnaissance est une
dérivation gauche car à chaque étape, c’est le symbole se trouvant en sommet de
pile qui est traité. Ce symbole correspond au symbole le plus à gauche dans la
proto-phrase correspondante.
T F a F a
+ + + + * * *
E E E E E E T T T T T a ε
On voit bien ici le rôle que joue le non déterminisme de A. Lorsqu’un non termi-
nal S doit être remplacé au sommet de la pile, il peut l’être par la partie droite
de n’importe quelle règle de la forme S → β. On ne sait pas à l’avance quelle
règle choisir. C’est là la difficulté principale de cette tâche. Elle est résolue dans
les automates à pile par la notion de non déterminisme qui permet de poursuivre
plusieurs hypothèses en parallèle. On peut aussi remarquer que si G est récursive
à gauche, P risque de ne jamais s’arrêter lors de la reconnaissance d’un mot.
q0 q1 q2
ε, ε −> S ε, Z0 −> Z0
Exemple :
L’automate à pile A1 correspondant à la grammaire G1 est défini de la façon
suivante :
BANDE D’ENTREE
UNITE DE CONTROLE
PILE
BANDE DE SORTIE
TETE D’ECRITURE
δ : Q × (Σ ∪ {ε}) × Γ → ℘(Q × Γ∗ × ∆∗ )
1 E →T +E 2E→T
3 T →F ∗T 4T →F
5 F → (E) 6F →a
1 4 6 2 3 6 4 6
E ⇒ T +E ⇒ F +E ⇒ a+E ⇒ a+T ⇒ a+F ∗T ⇒ a+a∗T ⇒ a+a∗F ⇒ a+a∗a
que l’on représentera par le mot 14623646
Soit une grammaire hors-contexte G dont les règles ont été numérotées de 1 à p.
On appelle un analyseur gauche de G, un transducteur à pile non déterministe TGg
qui produit pour une entrée w, une dérivation gauche de w.
T1g = h{q0 , q1 , q2 }, {a, +, ∗, (, )}, {E, T, F, Z0, +, ∗, a, (, )}, {1, 2, 3, 4, 5, 6}, δ, q0, Z0 , {q2 }i
avec :
δ(q0 , ε, Z0) = {(q1 , EZ0 , ε)} δ(q1 , +, +) = {(q1 , ε, ε)}
δ(q1 , ε, E) = {(q1 , T + E, 1), (q1 , T, 2)} δ(q1 , ∗, ∗) = {(q1 , ε, ε)}
δ(q1 , ε, T ) = {(q1 , F ∗ T, 3), (q1 , F, 4)} δ(q1 , (, () = {(q1 , ε, ε)}
δ(q1 , ε, F ) = {(q1 , (E), 5), (q1 , a, 6)} δ(q1 , ), )) = {(q1 , ε, ε)}
δ(q1 , a, a) = {(q1 , ε, ε)} δ(q1 , ε, Z0 ) = {(q2 , Z0 , ε)}
T1g analyse le mot a + a ∗ a en effectuant la séquence de mouvements suivante :
(q0 , a + a ∗ a, Z0 , ε) ⊢ (q1 , a + a ∗ a, EZ0 , ε)
⊢ (q1 , a + a ∗ a, T + EZ0 , 1)
⊢ (q1 , a + a ∗ a, F + EZ0 , 14)
⊢ (q1 , a + a ∗ a, a + EZ0 , 146)
⊢ (q1 , +a ∗ a, +EZ0 , 146)
⊢ (q1 , a ∗ a, EZ0 , 146)
⊢ (q1 , a ∗ a, T Z0 , 1462)
⊢ (q1 , a ∗ a, F ∗ T Z0 , 14623)
⊢ (q1 , a ∗ a, a ∗ T Z0 , 146236)
⊢ (q1 , ∗a, ∗T Z0, 146236)
⊢ (q1 , a, T Z0 , 146236)
⊢ (q1 , a, F Z0 , 1462364)
⊢ (q1 , a, aZ0 , 14623646)
⊢ (q1 , ε, Z0, 14623646)
⊢ (q2 , ε, Z0, 14623646)
Remarques :
– Si l’on ne s’intéresse qu’à une dérivation de m alors on peut s’arrêter après
avoir construit la première séquence de mouvements menant de la configuration
initiale à une configuration d’acceptation.
– Si on s’intéresse à toutes les dérivations de m, il faudra alors construire toutes
les séquences de mouvements.
– Si m n’est pas reconnu par TGg alors toutes les séquences de dérivations devront
être construites.
1 S → aSbS 2 S → aS 3 S → c
TGg = h{q0 , q1 , q2 }, {a, b, c}, {S, Z0}, {1, 2, 3}, δ, q0, Z0 , {q2 }i
Les différents mouvements que TGg peut décrire sur le mot aacbc à partir de la
configuration initiale (q0 , aacbc, Z0 , ε) sont représentés par l’arbre ci-dessous où
chaque nœud est étiqueté par une configuration et un identificateur (de la forme
Ci ) lui correspondant :
4
On suppose que toute séquence de mouvements que TGg peut décrire sur l’entrée m est de
taille finie.
C−1 (q0 , aacbc, Z0 , ε)
C5 (q1 , bc, bSbSZ0 , 113) C8 (q1 , bc, bSZ0 , 123) C12 (q1 , bc, bSZ0 , 213) C16 (q1 , bc, Z0 , 223)
C6 (q1 , c, SbSZ0 , 113) C9 (q1 , c, SZ0, 123) C13 (q1 , c, SZ0 , 213)
C7 (q1 , ε, bSZ0 , 113) C10 (q1 , ε, Z0, 1233) C14 (q1 , ε, Z0, 2134)
Une manière de construire toutes les analyses du mot aacbc consiste à déterminer
toutes les configurations d’acceptation atteignables à partir de C0 en effectuant
un parcours de l’arbre des configurations. Pour cela, on détermine l’ordre dans le-
quel seront visités les fils d’un nœud. Choisissons par exemple de visiter d’abord le
fils correspondant à l’application de la règle 1 puis celui qui correspond à la règle 2.
Performances :
– Espace : O(|m|)
– Temps : O(c|m| )
3.6.2 Analyseur prédictif non récursif
Nous allons voir dans cette section une méthode d’analyse descendante linéaire en
temps. Cette méthode ne peut être appliquée qu’à un sous-ensemble des gram-
maires hors-contexte appelées grammaires LL(k). La particularité de ces gram-
maires est que les analyseurs gauches qui leurs sont associés peuvent être rendus
déterministes si on s’autorise à regarder les k symboles suivant le caractère courant
dans le mot à analyser. Ce type d’analyse est dit prédictif . Dans la suite de cette
section, nous nous intéresserons uniquement au cas où k = 1 donc aux grammaires
et analyseurs LL(1).
Analyseurs LL(1)
Soit G = hN, Σ, P, Si une grammaire hors-contexte non ambiguë et m = a1 . . . an
un mot de L(G). On sait qu’il existe une unique dérivation gauche du mot m
composée des proto-phrases α1 . . . αk avec α1 = S et αk = m. L’idée de l’analyse
LL(1) est de construire cette suite de proto-phrases en ne lisant m qu’une fois, de
gauche à droite. Le principe est le suivant : si αi = a1 . . . aj Aβ alors αi+1 doit pou-
voir être déterminée de façon unique en fonction du symbole non terminal A et du
symbole aj+1. Une grammaire possédant cette propriété est dite grammaire LL(1).
Une grammaire LL(1) peut être analysée à l’aide d’un analyseur LL. Ce dernier
ressemble à un analyseur gauche, il possède en particulier une bande d’entrée, un
bande de sortie, une pile et une table d’analyse, comme l’illustre la figure 3.7.
BANDE D’ENTREE
TETE DE LECTURE
TABLE D’ANALYSE
PILE
BANDE DE SORTIE
TETE D’ECRITURE
1 E → T E′ 2 E ′ → +T E ′
3 E′ → ε 4 T → FT′
5 T ′ → ∗F T ′ 6 T′ → ε
7 F → (E) 8 F →a
a ( ) + ∗ $
E 1 1 erreur erreur erreur erreur
E′ erreur erreur 3 2 erreur 3
T 4 4 erreur erreur erreur erreur
T′ erreur erreur 6 6 5 6
F 8 7 erreur erreur erreur erreur
PREMIER et SUIVANT
Si α est une proto-phrase de G, premier(α) est l’ensemble des terminaux qui
commencent les chaı̂nes se dérivant de α. :
∗
premier(α) = {a ∈ Σ | α ⇒ au}
∗
Si α ⇒ ε alors ε appartient aussi à premier(α).
Pour calculer premier(X) avec X ∈ N ∪Σ, on applique les règles suivantes jusqu’à
ce qu’aucun terminal ni ε ne puisse être ajouté aux ensembles premier.
1. Si X ∈ Σ, premier(X) = {X}.
2. Si X → ε ∈ P , on ajoute ε à premier(X).
3. Si X ∈ N et X → Y1 . . . Yk ∈ P , mettre a dans premier(X) s’il existe
i tel que a est dans premier(Yi) et que ε est dans tous les premier(Y1 )
. . .premier(Yi−1 ). Si ε ∈ premier(Yj )∀j , 1 ≤ j ≤ k, on ajoute ε à
premier(X).
On calcule premier(X1 . . . Xn ) de la façon suivante :
1. Ajouter à premier(X1 . . . Xn ) tous les symboles de premier(X1 ) différents
de ε.
2. Si ε ∈ premier(X1 ), ajouter également les symboles de premier(X2 ) différents
de ε. Si ε ∈ premier(X2 ), ajouter également les symboles de premier(X3 )
différents de ε, etc.
3. Finalement, si ε appartient à premier(Xj ) pour tous les j = 1, 2, . . . n, on
ajoute ε à premier(X1 . . . Xn ).
Si A ∈ N, suivant(A) est l’ensemble des symboles a ∈ Σ qui peuvent apparaı̂tre
immédiatement à droite de A dans une proto-phrase :
∗
suivant(A) = {a ∈ Σ | S ⇒ αAaβ}
Si A peut être le symbole le plus à droite d’une proto-phrase alors $ est dans
suivant(A).
Pour calculer suivant(A) pour tous symbole non terminal A, on applique les
règles suivantes jusqu’à ce qu’aucun symbole non terminal ne puisse être ajouté
aux ensembles suivant :
1. Mettre $ dans suivant(S).
2. si A → αBβ, le contenu de premier(β), excepté ε, est ajouté à suivant(B).
3. s’il existe une règle A → αB ou une règle A → αBβ telle que ε ∈ premier(β)
∗
(c’est à dire β ⇒ ε), les éléments de suivant(A) sont ajoutés à suivant(B).
Exemple
Soit la grammaire G = h{E, E ′ , T, T ′ , F }, {a, +, ∗, (, ), a}, P, Ei non récursive à
gauche où P est composé des règles suivantes :
1 E → T E′ 2 E ′ → +T E ′
3 E′ → ε 4 T → FT′
5 T ′ → ∗F T ′ 6 T′ → ε
7 F → (E) 8 F →a
Alors :
premier(E) = premier(T ) = premier(F ) = {(, a}
premier(E ′ ) = {+, ε}
premier(T ′ ) = {∗, ε}
suivant(E) = suivant(E ′ ) = {), $}
suivant(T ) = suivant(T ′ ) = {+, ), $}
suivant(F ) = {+, ∗, ), $}
Méthode :
1. pour chaque regle i ∈ P de la forme A → α, procéder aux étapes 2 et 3.
2. Pour chaque symbole terminal a ∈ premier(α), ajouter i à M(A, a).
3. Si ε ∈ premier(α), ajouter i à M(A, b) pour chaque symbole terminal b ∈
suivant(A). Si ε ∈ premier(α) et $ ∈ suivant(A), ajouter i à M(A, $).
4. Mettre erreur dans toutes les entrées restées vides.
Si G n’est pas LL(1), en particulier si elle est récursive à gauche, non factorisée à
gauche ou ambiguë, M peut avoir des entrées qui sont définies de façons multiples.
On peut montrer qu’une grammaire G est LL(1) si et seulement si, pour toute
règle disctincte A → α et A → β de G, les conditions suivantes s’appliquent :
1. Pour aucun symbole terminal a, α et β ne se dérivent toutes les deux en des
mots commençant par a.
2. Une des deux proto-phrases α et β peut se dériver en ε.
∗
3. Si β ⇒ ε, α ne se dérive pas en un mot commençant par un élément de
suivant(A).
Index
Alphabet, 5 de Chomsky, 40
de pile, 44
non terminal, 7 Grammaire, 7
terminal, 7 LL(k), 55
Analyse ambiguë, 38
descendante, 53 dépendante du contexte, 10
prédictive, 55 factorisée à gauche, 44
Analyseur générative, 7
gauche, 52 hors contexte, 10
syntaxique, 50 récursive à gauche, 42
Arbre de dérivation, 38 régulière, 9
Automate sans cycles, 40
à pile, 48 sans restrictions, 10
complet, 22 Grammaires
déterministe, 23 équivalentes, 9
généralisé, 34 Hiérarchie de Chomsky, 10
minimal, 31
Axiome, 8 Langage
généré par une grammaire, 8
Chaı̂ne, 5 reconnaissable, 22
Concaténation de deux langages, 7 reconnu par un reconnaisseur, 12
Configuration
d’un automate à pile, 45 Mot, 5
Configuration d’un reconnaisseur, 11 Mouvement d’un reconnaisseur, 12
62
Symbole, 5
inaccessible, 39
inutile, 39
non terminal, 7
récursif, 42
à droite, 42
à gauche, 42
terminal, 7
Transducteur à pile, 50
Transition-ε, 23
Type
d’un langage, 10