Sunteți pe pagina 1din 63

Eléments de Théorie des langages

Notes de cours de SHS 18

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 Langages hors contexte 39


3.1 Grammaires hors-contexte . . . . . . . . . . . . . . . . . . . . . . . 39
3.1.1 Sens de dérivation . . . . . . . . . . . . . . . . . . . . . . . . 39
3.1.2 Arbre de dérivation . . . . . . . . . . . . . . . . . . . . . . . 40
3.1.3 Ambiguı̈té . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.2 Transformation de grammaires . . . . . . . . . . . . . . . . . . . . . 41
3.2.1 Forme normale de Chomsky . . . . . . . . . . . . . . . . . . 42
3.2.2 Grammaires non récursives à gauche . . . . . . . . . . . . . 44
3.2.3 Factorisation à gauche . . . . . . . . . . . . . . . . . . . . . 46
3.3 Automate à pile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.3.1 Représentation graphique d’un automate à pile . . . . . . . 48
3.3.2 Reconnaissance d’un mot par un automate non déterministe 49
3.4 Automate à pile ⇔ Grammaires hors-contexte . . . . . . . . . . . . 50

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

L’objet de ce chapitre est d’introduire les trois notions fondamentales de ce cours


que sont les langages, les grammaires et les reconnaisseurs.

1.1 Le paysage syntaxique


L’univers de la théorie des langages est peuplé de symboles appartenant à des al-
phabets, de mots et de langages.

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.

Un alphabet est un ensemble fini de symboles . L’ensemble des 26 lettres de l’al-


phabet romain (que l’on notera R) et l’ensemble (noté B) des deux symboles 0 et
1, sont deux exemples d’alphabets. On désigne conventionnellement un alphabet
par la lettre grecque Σ.

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 .

La concaténation de deux mots α et β, notée α · β ou simplement αβ est le mot


obtenu en juxtaposant les symboles de β à la suite de ceux de α. Si α = abra et
1
On pourra remarquer que l’expression a avec a ∈ Σ dénote deux objets différents, le symbole
a et le mot de longueur 1 composé du symbole a. Cette ambiguı̈té n’est pas gênante et nous
garderons donc cette même expression pour dénoter les deux objets.
2
Attention, même si personne ne nous en empêche, c’est une très mauvaise idée d’utiliser ε
comme symbole appartenant à un alphabet, car on ne peut plus distinguer le mot de longueur 1
composé du symbole ε du mot vide !

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 :

B ∗ = {ε, 0, 1, 10, 00, 01, 10, 11, 001...}


Un langage sur un alphabet Σ est un ensemble de mots construits sur Σ. Tout
langage défini sur Σ est donc une partie de Σ∗ .

Deux langages sont définis indépendamment de tout alphabet. Il s’agit du langage


vide (noté ∅) et du langage composé uniquement du mot vide ({ε}). Σ peut être
vu comme le langage composé des symboles de Σ.

1.1.1 Opérations sur les langages


Les langages étant des ensembles, on peut leur appliquer les opérations définies
sur ces derniers :

– L’union de deux langages L1 et L2 , est le langage, noté L1 ∪ L2 constitué des


mots appartenant à L1 ou à L2 .

L1 ∪ L2 = {x|x ∈ L1 ou x ∈ L2 }

– L’intersection de L1 et L2 , est le langage, noté L1 ∩ L2 constitué des mots


appartenant à L1 et à 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.

Pour alléger les notations, nous représenterons par :

α → β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.

Plus formellement, une grammaire est un quadruplet hN, Σ, P, Si où :

– N est un ensemble de symboles non terminaux, appelé l’alphabet non terminal.

– Σ est un ensemble de symboles terminaux, appelé l’alphabet terminal, tel que


N et Σ soient disjoints.

4
– P est un sous ensemble fini de :

(N ∪ Σ)∗ N(N ∪ Σ)∗ × (N ∪ Σ)∗

un élément (α, β) de P , que l’on note α → β est appelé une règle de production
ou règle de réécriture.

– S est un élément de N appelé l’axiome de la grammaire.

Une grammaire G = hN, Σ, P, Si définit un langage de manière récursive. Pour


décire le processus de génération, nous allons commencer par définir un type de
mot particulier appelé proto-phrase d’une grammaire. Les proto-phrases de G sont
des mots construits sur l’alphabet Σ ∪ N, on les définit récursivement de la façon
suivante :

– S est une proto-phrase de G

– si αβγ est une proto-phrase de G et β → δ ∈ P alors αδγ est une proto-phrase


de G.

Une proto-phrase de G ne contenant aucun symbole non terminal est appelé un


mot généré par G. Le langage généré par G, noté L(G) est l’ensemble des mots
générés par G.

L’opération qui est au cœur du processus de génération et qui consiste à générer


une proto-phrase αδγ à partir d’une proto-phrase αβγ et d’une règle de production
r de la forme β → δ est appelée l’opération de dérivation. Elle se note à l’aide d’une
double flèche :

αβγ ⇒ αδγ
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.

1.2.1 Hiérarchie des grammaires


Les grammaires peuvent être classées en fonction de la forme de leurs règles de
production. On définit cinq types de règles de production :

– règles régulières à gauche :


Une règle est régulière à gauche si et seulement si elle est de la forme A → xB
ou A → x avec A, B ∈ N et x ∈ Σ∗ .

– règles régulières à droite :


Une règle est régulière à gauche si et seulement si elle est de la forme A → Bx
ou A → x avec A, B ∈ N et x ∈ Σ∗ .

– 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.

Cette classification des règles de production permet de définir un classement des


grammaires selon le type de leurs règles. Etant donné une grammaire G = hN, Σ, P, Si,
on dira que G est :

– régulière (ou grammaire de type 3) si elle est régulière à droite ou régulière à


gauche. Une grammaire est régulière à gauche si toutes ses règles sont régulières à
gauche et une grammaire est régulière à droite si toutes ses règles sont régulières
à droite. Une grammaire qui aurait des règles régulières à gauche et des règles
régulières à droite n’est pas une grammaire régulière.

– hors contexte (ou grammaire de type 2) si toutes ses règles de production sont
hors contexte.

– dépendante du contexte (ou grammaire de type 1) si toutes ses règles de produc-


tion sont dépendantes du contexte.

– sans restrictions (ou grammaire de type 0) si toutes ses règles de production


sont sans restrictions.

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 sans restrictions

grammaires contextuelles

grammaires hors-contexte

grammaires régulières

Fig. 1.1 – hierarchie de Chomsky

1.2.2 Type d’un langage


La classification des grammaires ci-dessus va permettre de classer les langages se-
lon le type de grammaires nécessaire à leur génération. Un langage pouvant être
généré par une grammaire de type x et pas par une grammaire d’un type supérieur
dans la hiérarchie, sera appelé un langage de type x.

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.

– langages hors contextes (de type 2)


an bn , avec n ≥ 0 (le langage des mots composés d’un certain nombre de a
suivi du même nombre de b), qui peut être généré par la grammaire suivante :
h{S}, {a, b}, {S → aSb|ε}, Si.

langage mirroir, le langage des mots de la forme mm avec m ∈ Σ∗ : h{S}, {a, b}, {S →
aSa|bSb|aa|bb}, Si.

– langages contextuels (de type 1)


an bn cn h{S, S1 , S2 }, {a, b, c}, {S → aS1 c, S1 → b|SS2 , cS2 → S2 c, bS2 → 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.

Un reconnaisseur est composé de quatre parties :


1. une bande de lecture, qui est une succession de cases, chaque case pouvant
contenir un seul symbole d’un alphabet d’entrée. C’est dans les cases de cette
bande de lecture qu’est écrit le mot à reconnaı̂tre.

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.

Les différents éléments d’un reconnaisseur sont représentés graphiquement dans la


figure 1.2.

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

Fig. 1.2 – Eléments d’un reconnaisseur

2. Le contenu de la bande de lecture et la position de la tête de lecture


3. Le contenu de la mémoire
Un reconnaisseur fonctionne en effectuant une séquence de mouvements. Un mou-
vement est le passage d’une configuration du reconnaisseur à une autre. Le passage
de la configuration C1 à la configuration C2 est représenté de la façon suivante :
k ∗
C1 ⊢ C2 . Une suite de k mouvements est notée ⊢. On définit les deux notations ⊢
+
et ⊢ pour k ≥ 0 et k > 0.

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.

Un reconnaisseur est dit déterministe si pour chaque configuration, il existe au


plus un mouvement possible sinon, il est dit non déterministe.

La configuration initiale d’un reconnaisseur est une configuration pour laquelle


l’unité de contrôle est dans un état initial, la tête de lecture se trouve sur la case
se trouvant la plus à gauche de la bande de lecture et la mémoire contient un
symbole initial donné.

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

2.1 Expressions régulières


Etant donné un alphabet Σ, on appelle ensemble régulier sur Σ un langage sur Σ
défini de la façon suivante :
1. ∅ (l’ensemble vide) est un ensemble régulier sur Σ.
2. {ε} est un ensemble régulier sur Σ.
3. {a} est un ensemble régulier sur Σ pour tout a ∈ Σ.
4. Si P et Q sont des ensembles réguliers sur Σ, alors les ensembles suivants
sont des ensembles réguliers :
(a) P ∪ Q
(b) P Q
(c) P ∗
5. rien d’autre n’est un ensemble régulier.
On dit que la famille des ensembles réguliers est fermée pour les opérations de
concaténation, union et étoile1 . De façon générale, on dit qu’une famille d’objets
est fermée pour une opération si l’applicaton de cette opération à des objets de la
famille produit un objet qui appartient à cette famille.

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.

L’expression régulière (0 + (1(0)∗ )) définie sur l’alphabet {0, 1} dénote l’ensemble


{0} ∪ ({1}({0})∗), qui est l’ensemble formé du mot 0 et des mots composés d’un
un 1 suivi d’un nombre quelconque de 0 : {0, 1, 10, 100, . . .}. E étant une ex-
pression régulière, on notera L(E) le langage dénoté par E : L(0 + (1(0)∗ )) =
{0, 1, 10, 100, . . .}.

Quelques exemples d’expressions régulières sur Σ = {0, 1} :

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.1 Manipulation d’expressions régulières


Les opérations d’union, de concaténation et l’étoile de Kleene sont appelées des
opérations régulières . On peut faire le parallèle entre les expressions arithmétiques
qui sont construites à l’aide d’opérateurs arithmétiques et les expressions régulières,
construites à l’aide d’opérateurs réguliers. Dans un cas ces expressions dénotent
des nombres et dans l’autre, elles dénotent des ensembles. Afin d’alléger l’écriture
des expressions régulières en évitant certaines parenthèses, nous respecterons les
priorités suivantes : l’étoile est prioritaire sur la concaténation qui est prioritaire
sur l’union :

priorité(∗) > priorité(·) > priorité(+)


L’expression 0 + 10∗ est donc équivalente à (0 + (1(0)∗ )). On dira que deux expres-
sions régulières sont équivalentes (=) si elles dénotent le même ensemble.
Voici quelques lois qui permettent de simplifier des expressions régulières.

α + (β + γ) = (α + β) + γ (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 :

αX + β = αα∗ β + β = (αα∗ + ε)β = α∗ β


On peut de la même façon définir des systèmes d’équations régulières.

2.2 Expressions régulières ⇔ grammaires régulières


La raison pour laquelle nous avons défini les ensembles réguliers dans ce chapitre
est qu’il existe une relation tout à fait privilégiée entre les langages réguliers et les
ensembles réguliers qui est donnée par le théorème suivant :
P ⊂ Σ∗ est un ensemble régulier si et seulement si P est un langage régulier.

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.

2.2.1 Expressions régulières ⇒ grammaires régulières


La définition des ensembles réguliers (2.1) distinguait six cas. Les trois premiers
affirmaient que ∅, ε et a ∈ Σ étaient des ensembles réguliers et les trois derniers af-
firmaient que les ensembles réguliers étaient fermés pour les opérations régulières.
Nous allons montrer, dans les trois premiers cas, que ∅, ε et a ∈ Σ peuvent être
générés par des grammaires régulières et nous montrerons ensuite que les lan-
gages réguliers sont fermés pour les opérations régulières. On montre que la classe
des langages réguliers est fermée pour une opération donnée si étant donné deux
grammaires régulières G1 et G2 , on peut construire la grammaire G qui génère le
langage produit par l’application de cette opération aux deux langages L(G1 ) et
L(G2 ). Dans la suite, les deux grammaire G1 et G2 sont définies respectivement
par hN1 , Σ, P1 , S1 i et hN2 , Σ, P2 , S2 i.
1. R = ∅. R dénote le langage ∅ qui est aussi le langage généré par la grammaire
régulière suivante :

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

3. R = a avec a ∈ Σ. R dénote le langage {a} qui est aussi le langage généré


par la grammaire régulière suivante :

G = h{S}, Σ, {S → a}, Si

4. Si L1 et L2 sont des langages réguliers, générés par les grammaires G1 et G2


alors L1 ∪ L2 est décrit par la grammaire :

G = hN1 ∪ N2 ∪ {S}, Σ, P1 ∪ P2 ∪ {S → S1 |S2 }, Si

où S est un nouveau symbole non terminal tel que S ∈


/ N1 et S ∈
/ N2 .

Il faut encore montrer que L(G) = L(G1 ) ∪ L(G2 ) !


5. Si L1 et L2 sont des langages réguliers, générés par les grammaires G1 et G2
alors L1 L2 est généré par la grammaire :

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 :

a+b : {S3 → S1 |S2 , S1 → a , S2 → b}


(a + b)∗ : {S4 → S3 |ε , S3 → S1 |S2 , S1 → aS4 , S2 → bS4 }
aba : {S5 → aS6 , S6 → bS7 , S7 → a}

(a + b) aba : {S4 → S3 |S5 , S3 → S1 |S2 , S1 → aS4 , S2 → bS4 , S5 → aS6 , S6 → bS7 , S7 → a}

2.2.2 Grammaires régulières ⇒ expressions régulières


Soit la grammaire G = hN, Σ, P, Si avec N = {A1 , . . . , An }. On peut construire le
système d’équations ayant les éléments de N comme inconnues.

L’équation correspondant à Ai est : Ai = αi0 + αi1 A1 + . . . + αin An avec :


2
Pour alléger les notations, nous n’écrirons que les productions des grammaires, en respectant
la convention suivante : la partie gauche de la première production est l’axiome de la grammaire.
– αi0 = a1 + . . . + ak où Ai → a1 | . . . |ak sont toutes les productions ayant Ai
comme partie gauche et un terminal comme partie droite. Si k = 0 alors αi0 = ∅.

– αij = a1 + . . . + am (pour j > 0) où Ai → a1 Aj | . . . |am Aj sont toutes les produc-


tions ayant Ai comme partie gauche et une partie droite se terminant par Aj .
Si m = 0 alors αij = ∅.

L’expression régulière correspondant à L(G) est la valeur de la variable S dans la


solution de ce système d’équations.

Exemple : Ecrivons le système d’équations régulières correspondant à la gram-


maire de l’expression (a + b)∗ aba construite ci-dessus.

S4 = S3 + S5 (2.12) S5 = aS6 (2.16)


S3 = S1 + S2 (2.13) S6 = bS7 (2.17)
S1 = aS4 (2.14) S7 = a (2.18)
S2 = bS4 (2.15)

Des équations 2.16, 2.17 et 2.18, on peut déduire l’équation :

S5 = aba (2.19)
Des équations 2.13, 2.14 et 2.15, on peut déduire :

S3 = aS4 + bS4 (2.20)


En remplaçant 2.19 et 2.20 dans 2.12, on obtient l’équation à une inconnue sui-
vante :

S4 = aS4 + bS4 + aba (2.21)


que l’on peut écrire sous la forme :

S4 = (a + b)S4 + aba (2.22)


dont une solution est :

S4 = (a + b)∗ aba (2.23)

2.3 Automates finis


Les automates finis (on dira indiféremment automate fini ou automate dans la
suite de ce chapitre) constituent un type de reconnaisseurs. Comme nous l’avons
vu en 1.3, un reconnaisseur est composé d’une bande d’entrée, d’une tête de lecture,
d’une mémoire et d’une unité de contrôle. Les automates finis comptent parmi les
reconnaisseurs les plus simples, du fait que leur mémoire est nulle. De plus, la tête
de lecture ne se déplace que d’une case vers la droite à chaque mouvement du
reconnaisseur.
Un automate fini est donc défini par un ensemble d’états, qui sont les différents
états possibles de son unité de contrôle, et par une fonction de transition qui as-
socie un état e à un couple (q, a) formé d’un état et d’un symbole. On dit que
l’automate passe de l’état q à l’état e en lisant le symbole a ou encore que l’au-
tomate transite vers e sur a. Parmi les états de l’unité de contrôle, un état est
distingué comme étant l’état initial et un sous ensemble des états définit les états
d’acceptation de l’automate.

Plus formellement, un automate fini A est un quintuplet hQ, Σ, δ, q0 , F i où :


– Q est l’ensemble des états
– Σ est l’alphabet d’entrée
– δ est la fonction de transition3 :

δ :Q×Σ→ Q

– q0 est l’état initial


– F ⊆ Q est l’ensemble des états d’acceptation
Exemple :

A2n = h{A, B}, {0, 1}, δ, A, {B}i


avec : δ(A, 1) = A, δ(A, 0) = B, δ(B, 0) = B, δ(B, 1) = A. L(A2n ) est l’ensemble
des nombres pairs en représentation binaire.

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 mouvement de l’automate consiste à lire le symbole se trouvant sous sa tête


de lecture, à changer d’état (si cela est possible) et à déplacer sa tête de lecture
d’une case vers la droite, ce que l’on représente de la façon suivante :

(q, aw) ⊢ (q ′ , w) si δ(q, a) = q ′

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 }

Il est très facile de déterminer si un automate fini déterministe accepte un mot m


étant donné qu’il existe au plus une séquence de mouvements pouvant mener de
(q0 , m) à (q, ε) avec q ∈ F .

Exemple : l’unique séquence de mouvements de A2n correspondant à l’acceptation


du mot 0100 est la suivante :

(A, 0100) ⊢ (B, 100) ⊢ (A, 00) ⊢ (B, 0) ⊢ (B, ε)

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).

2.3.1 Automate complet


Un automate A = hQ, Σ, δ, q0 , F i est complet si A peut transiter depuis chaque
état vers un autre état sur tous les symboles de Σ, ce qui revient à dire que pour
tout état q et tout symbole a, il existe un état e ∈ Q tel que δ(q, a) = e.

Si un automate n’est pas complet, on peut le compléter en lui ajoutant un nouvel


état, qui n’est pas un état d’acceptation, appelé état puits (noté conventionnelle-
ment par le symbole ∅), dans lequel aboutiront toutes les transitions qui “man-
quaient”.

2.3.2 Représentation graphique d’un automate fini


Les automates finis sont souvent représentés sous la forme d’un graphe dont les
sommets sont les états de l’automate et les arcs (étiquetées par les symboles de Σ)
correspondent à la fonction de transition δ : il existe un arc étiqueté par a entre les
sommets i et j si et seulement si δ(a, i) = j. Les états initiaux sont désignés par
une flèche entrante et les états d’acceptation par un double cercle, comme dans la
figure 2.1.

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

Fig. 2.1 – Représentation graphique d’un automate

2.3.3 Représentation tabulaire d’un automate fini


On peut aussi représenter l’automate A = hQ, Σ, δ, q0 , F i sous forme d’un tableau
T indicé par Q et Σ tel que q ′ ∈ T [q, a] si et seulement si δ(q, a) = q ′ . On distingue
l’état initial et les états d’acceptation par des flèches dirigées respectivement vers
la droite et vers la gauche, comme l’illustre la figure 2.3.3.

0 1
→ A B A
← B B A
Fig. 2.2 – Représentation tabulaire d’un automate

Dans la suite de ce document, nous utiliserons indifféremment la représentation


formelle, la représentation graphique ou la représentation tabulaire.

2.3.4 Automates non déterministes


Les automates finis, tels que nous les avons définis en 2.3 possèdent une propriété
que nous avons déjà rencontré en 1.3 qui est le déterminisme : pour toute configu-
ration d’un automate fini, il existe au plus un mouvement possible. Un automate
est non déterministe s’il existe des configurations pour lesquelles plus d’un mou-
vement est possible.

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

Fig. 2.3 – Représentation graphique d’un automate non déterministe

Reconnaissance d’un mot par un automate non déterministe

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.

Illustrons cela grâce à l’automate N défini ci-dessous et qui reconnait le langage


des mots construits sur {a, b} de longueur supérieure ou égale à 2 et dont l’avant-
dernier symbole est un a.
N = h{0, 1, 2}, {a, b}, δn, 0, {2}i avec :
δn (0, a) = {0, 1}, δn (1, a) = {2}, δn (0, b) = {0} et δn (1, b) = {2}.

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)

(0, abab) (2, abab)


H
 H
 H
(1, bab) (0, bab)

(2, ab) (0, ab)


HH
(1, b) (0, b)

(2, ε) (0, ε)
Fig. 2.4 – Reconnaissance non déterministe

Déterminisation d’un automate


Les automates finis déterministes et non déterministes reconnaissent la même
classe de langages. Ce résultat est à la fois surprenant et pratique. Il est sur-
prenant car les automates non déterministes semblent plus puissants que les au-
tomates déterministes. Il est pratique car il est souvent plus simple de décrire un
langage à l’aide d’un automate non déterministe.

Nous allons démontrer ce résultat en décrivant une méthode permettant de trans-


former un automate non déterministe en un automate déterministe reconnaissant
le même langage5 .

Soit N = hQN , Σ, δN , qN , FN i un automate non déterministe reconnaissant un


langage L. On construit un automate détermisite D = hQD , Σ, δD , qD , FD i qui re-
connaı̂t le même langage. L’idée générale de la construction consiste a créer des
états qui correspondent à des ensembles d’états de N. Ainsi, lorsque N peut tran-
siter d’un état e vers les états q1 , . . . , qi sur un symbole a, un nouvel état q1,...,i
correspondant à cet ensemble est créé et les différentes transitions sont remplacées
par une transition de e vers q1,...,i sur a.

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.

Elimination des transitions-ε

Etant donné un automate N = hQN , Σ, δN , qN , FN i, on lui associe un automate


N ′ = hQN ′ , Σ, δN ′ , qN ′ , FN ′ i sans transitions-ε en procédant comme suit :
– Tant qu’il existe au moins une transition-ε, on applique la procédure suivante :
5
Il n’est pas nécessaire de montrer l’inverse car la définition des automates non déterministes
englobe celle des automates déterministes.
ε q
x
r k
ε q’
x
q
r k
q’
x

Fig. 2.5 – Elimination de transitions-ε


δ(a,R)
a
R

a
a
a

Fig. 2.6 – Calcul de la fonction de transition d’un automate non déterministe

– On choisit un état k dans lequel aboutit au moins une transition-ε


– pour tout q ∈ QN − {k} tel que δ(q, ε) = k, et pour tous r ∈ Q et x ∈ Σε tels
que δ(k, x) = r, on ajoute une transition δ(q, x) = r.
– on supprime les transitions δ(q, ε) = k (cette étape et la précédente sont
représentées dans la figure 2.3.4)
– si k ∈ F , on ajoute q à F
– si k n’est plus accessible, on le supprime.
Réduction des transitions

Etant donné un automate N ′ sans transitions-ε, on lui associe un automate déterministe


D = hQD , Σ, δD , qD , FD i défini comme suit :
1. QD = ℘(QN ′ ) Les états de D sont des ensembles d’états de N ′ .

2. Pour R ∈ QD et a ∈ Σ, on calcule δD (R, a) de la façon suivante :

δD (R, a) = {q ∈ Q|q ∈ δN ′ (r, a) avec r ∈ R}

Si R est un état de D alors c’est aussi un ensemble d’états de N ′ . Lorsque


D lit un symbole a en R, il transite vers un état correspondant à tous les
états que l’on peut atteindre à partir d’un état r de R par une transition
en a. Mais δN ′ (r, a) peut être lui-même un ensemble d’états (car N ′ est
non déterministe), il faut donc prendre l’union de tous ces ensembles (voir
figure 2). Ce que l’on peut écrire de la façon suivante :
[
δD (R, a) = δN ′ (r, a)
r∈R
3. qD = {qN ′ }. L’état initial de D est l’ensemble constitué de l’état initial de N ′ .

4. FD = {R ∈ QD |R contient un état d’acceptation de N ′ }. Les états d’accep-


tation de D sont les ensembles qui contiennent au moins un état d’acceptation
de N ′ .

Dans la pratique, lorsque l’on veut construire un automate déterministe D à partir


d’un automate non déterministe sans transitions-ε N ′ , on ne commence pas par
créer tous les états de D, car ils peuvent être nombreux : |℘(Q)| = 2|Q| !

On construit plutôt les états de D au fur et à mesure de leur création en partant


de l’état initial. Illustrons cela sur l’automate N ′ (de la partie 2.4) représenté
ci-dessous sous une forme tabulaire :

a b
→ 0 {0, 1} 0
1 2 2
← 2 ∅ ∅

On part de l’état initial 0 dont on calcule les transitions :

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

2.3.5 Propriétés de fermeture


Nous allons montrer que la classe des langages reconnaissables (les langages pou-
vant être reconnus par des automates finis) est fermée pour un certain nombre
d’opérations. On montre que la classe des langages reconnaissables est fermée pour
une opération donnée si étant donné deux automates A1 et A2 on peut construire
l’automate A qui reconnaı̂t le langage produit par l’application de cette opération
aux deux langages L(A1 ) et L(A2 ). Nous allons décrire dans les cinq sections sui-
vantes comment construire les automates reconnaissant successivement l’union, la
concaténation, l’étoile, la complémentation et l’intersection de deux langages re-
connaissables. Dans la suite, les trois automates A, A1 et A2 sont définis par les
quintuplets suivants : hQ, Σ, δ, q0 , F i, hQ1 , Σ1 , δ1 , q1 , F1 i et hQ2 , Σ2 , δ2 , q2 , F2 i
Union
On construit l’automate A tel que L(A) = L(A1 ) ∪ L(A2 ). L’idée est de créér un
nouvel état initial duquel on peut acceder aux états initiaux de A1 et de A2 par
des transitions-ε. Ainsi si un mot m est reconnu par A1 ou par A2 , il est reconnu
par A car sans lire un symbole de m, on peut accéder à l’état initial de A1 et
de A2 . Cette construction est représentée graphiquement dans la figure 2.7. On
remarquera que A est non déterministe.

A1UA2

A1

A2
ε

Fig. 2.7 – Union de deux automates

Plus formellement, A est défini de la façon suivante :

1. Q = {q0 } ∪ Q1 ∪ Q2 . L’ensemble des états de A est constitué des états de A1 ,


des états de A2 et d’un nouvel état initial q0 .
2. l’état q0 est l’état initial de A.
3. F = F1 ∪ F2 . L’ensemble des états d’acceptation A est constitué des états
d’acceptation de A1 et des états d’acceptation de A2 .
4. La fonction de transition δ est définie de la façon suivante pour tout q ∈ Q
et tout a ∈ Σε :


 δ1 (q, a) si q ∈ Q1

 δ2 (q, a) si q ∈ Q2
δ(q, a) =


 {q1 , q2 } si q = q0 et a = ε

∅ si q 6 ε
= q0 et a =

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 :

1. Q = Q1 ∪ Q2 . L’ensemble des états de A est constitué des états de A1 et des


états de A2 .
A1 A2

A1A2

Fig. 2.8 – Concaténation de deux automates

2. q0 = q1 . L’état initial q0 est le même que celui de A1 .


3. F = F2 . L’ensemble des états d’acceptation celui de A2 .
4. La fonction de transition δ est définie de la façon suivante pour tout q ∈ Q
et tout a ∈ Σε :


 δ1 (q, a) si q ∈ Q1 et q ∈/ F1

 δ1 (q, a) si q ∈ F1 et a 6= ε
δ(q, a) =


 δ1 (q, a) ∪ {q2 } si q ∈ F1 et a = ε

δ2 (q, a) si q ∈ Q2

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∗
ε

Fig. 2.9 – Etoile d’un automate

Formellement :

1. Q = {q0 } ∪ Q1 . L’ensemble des états de A1 plus un nouvel état initial q0 .


6
On pourrait croire qu’il suffit de faire de l’état initial de A1 un état d’acceptation, ce n’est
en fait pas le cas, car cette méthode, bien qu’elle permette la reconnaissance de ε par A, risque
de permettre aussi la reconnaissance d’autres mots indésirables (s’il existe des transitions vers
l’état initial), ce qui n’est pas le cas dans la construction proposée.
2. q0 = q1 . L’état q0 est l’état initial de A∗1 .
3. F = {q0 } ∪ F1 . L’ensemble des états d’acceptation A est constitué des états
d’acceptation de A1 et du nouvel état initial.
4. La fonction de transition δ est définie de la façon suivante pour tout q ∈ Q
et tout a ∈ Σε :




δ1 (q, a) si q ∈ Q1 et q ∈/ F1



 δ1 (q, a) si q ∈ F1 et a 6= ε
δ(q, a) = δ1 (q, a) ∪ {q1 } si q ∈ F1 et a = ε




 {q1 } si q = q0 et a = ε

 ∅ si q = q0 et a 6= ε

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.

Il est indispensable que A1 soit déterministe et complet. En effet, puisque l’on


échange les états d’acceptation et les états de non-acceptation, il ne faut pas que
dans A1 , un même mot soit étiquette à la fois d’un chemin menant à un état d’ac-
ceptation et d’un chemin menant à un état de non-acceptation, car ce serait aussi
le cas dans A et ce mot appartiendrait à la fois à L et à L̄, ce qui est impossible.

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 :

A = hQ1 × Q2 , Σ, δ, (q1 , q2 ), F1 × F2 i avec :


1. δ((e1 , e2 ), a) = (δ1 (e1 , a), δ2 (e2 , a))∀a ∈ Σ, ∀(e1 , e2 ) ∈ Q1 × Q2
En pratique, la construction de A en suivant ce principe peut être fastidieuse,
car ce dernier possède un grand nombre d’états : |Q1 | × |Q2 |. En général, un
nombre important de ces états sont “inutiles” car ils sont non accessibles ou non
co-accessible. Il vaut donc mieux éviter de les créer. Pour cela, on part de deux
automates déterministes complets A1 et A2 :
– on commence par créer l’état de départ (q1 , q2 )
– pour chaque symbole a ∈ Σ, et chaque état (e1 , e2 ), il y aura une transition :
– δ ′ ((e1 , e2 ), a) = (e′1 , e′2 ) si δ1 (e1 , a) = e′1 et δ2 (e2 , a) = e′2
– δ ′ ((e1 , e2 ), a) = ∅ sinon
On recommence ce travail depuis chacun des nouveaux états (e′1 , e′2 ) ainsi créés
et on s’arrête quand plus aucun nouvel état est créé. Les états d’acceptation
sont tous les états (e1 , e2 ) tels que e1 ∈ F1 et e2 ∈ F2 .
L’automate ainsi réalisé est déterministe complet.
Exemple

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’automate minimal qui reconnaı̂t un langage donné est unique, à la numérotation


des états près.

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.

Avant de décrire la méthode de construction d’un automate minimal, on définit la


notion de séparation de deux états :

Soit A = hQ, Σ, δ, q0 , F i un automate fini déterministe complet. Deux états s, t ∈ Q


sont séparés par le mot u ∈ Σ∗ si le chemin étiqueté par ce mot en partant de l’un
des deux états aboutit à un état d’acceptation tandis que le chemin étiqueté par
ce mot et partant de l’autre état aboutit dans un état qui n’est pas un état d’ac-
ceptation :
∗ ∗
– ou bien (s, u) ⊢ (q, ε) avec q ∈ F et (t, u) ⊢ (q, ε) avec q ∈
/F
∗ ∗
– ou bien (t, u) ⊢ (q, ε) avec q ∈ F et (s, u) ⊢ (q, ε) avec q ∈
/F
Remarques :
– Deux états sont séparés par ε si et seulement si l’un des deux états appartient
à F et l’autre à Q − F .

– 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.

La construction se fait de manière itérative, en partant d’une partition initiale qui


est affinée au fur et à mesure. La partition initiale consiste en deux parties : les
états d’acceptation et les états de non acceptation (ces deux parties sont séparées
par ε). L’étape fondamentale consiste à prendre une partie G et un symbole a
et à étudier les transitions des états de G sur a. Si ces transitions conduisent à
des états appartenant à des parties différentes dans la partition courante, alors on
doit diviser G de façon que les transitions sur a depuis chaque partie mènent à
des états appartenant à la même partie de la partition courante. Ce processus est
répété jusqu’à ce que plus aucune partie n’ait besoin d’être divisée.

Entrée : A = hQ, Σ, δ, q0 , F i un automate déterministe complet


Sortie : Un automate minimal A′ = hQ′ , Σ, δ ′ , q0′ , F ′ i qui reconnaı̂t le même langage
que A.
Méthode :

1. Construire une partition initale Π de Q composée de deux parties : les états


d’acceptation F et les états de non acceptation Q − F .
2. Construire une nouvelle partition Πn à partir de Π de la façon suivante :
pour chaque partie P de Π :

– partitionner P en sous-groupes de manière que deux états e et t apparte-


nant à P appartiennent dans le même sous-groupe si et seulement si, pour
tout symbole a ∈ Σ, les états e et t ont des transitions sur a vers des états
de la même partie de Π : (au pire, un état formera un sous-groupe par
lui-même) remplacer P dans Π par tous les sous-groupes ainsi formés.

3. Si Πn = Π, aller à l’étape 4, sinon répéter l’étape 2 avec Π ← Πn .


4. Choisir un état dans chaque partie de la partition Π comme représentant de
ce groupe.
– Ces états constituent Q′ , les états de l’automate minimal.
– La fonction de transition δ ′ est construite de la façon suivante : Pour chaque
état q de Q′ , si δ(q, a) = e alors δ ′ (q, a) = e′ où e′ est le représentant de la
partie de e.
– q0′ est le représentant de la partie de q0 .
– F ′ est l’ensemble composé des représentants des parties des éléments de
F.
5. Si A′ possède des états puits, les supprimer, supprimer aussi tous les états
non accessibles.

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

2.4 Expressions régulières ⇔ automates finis


Les langages reconnaissable ont été définis indépendamment des langages réguliers,
pour pouvoir dire que les automates finis constituent des reconnaisseurs pour les
langages réguliers, il nous manque un élément, qui est donné par le Théorème de
Kleene :

P ⊂ Σ∗ est un ensemble régulier si et seulement si il est défini par un automate


fini.
On a dit par ailleurs (section 2.1) que les ensembles réguliers pouvaient être décrits
par des grammaires régulières, il en résulte par conséquent que les automates finis
constituent des reconnaisseurs pour langages réguliers.

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.4.1 Expression régulière ⇒ automate


Pour construire un automate correspondant à une expression régulière, nous allons
procéder comme nous l’avons fait pour en ?? construire une grammaire régulière
à partir d’une expression régulière. Pour chacun de ces six cas, de la définition des
expressions régulières, en 2.1, nous allons construire un automate reconnaissant le
même langage.
1. E = ∅. E dénote le langage ∅ qui est aussi le langage reconnu par l’automate
suivant : A = h{q}, Σ, δ, q, ∅i avec δ(r, b) = ∅, ∀r, ∀b.

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.

3. E = a avec a ∈ Σ. E dénote le langage {a} qui est aussi le langage re-


connu par l’automate suivant : A = h{q1 , q2 }, Σ, δ, q1 , {q2 }i avec δ(q1 , a) = q2 ,
δ(r, b) = ∅ pour r 6= q1 ou b 6= a.

4. E = E1 + E2

5. E = E1 E2

6. E = E1∗

Les trois derniers cas ont été traités en 2.3.5.

La construction de l’automate correspondant (a + b)∗ aba est représentée dans la fi-


gure 2.10. On commence par décomposer l’expression régulière en sous-expressions
régulières élémentaires que l’on combine ensuite.
a: a b: b

a
ε
a+b :
ε b

ε
a
ε
(a+b)* : ε

ε b

aba : a ε b ε a

ε
a
ε
ε
(a+b)*aba :
ε b ε

ε
ε ε

ε b ε a
a

Fig. 2.10 – Construction de l’automate correspondant à (a + b)∗ aba


2.4.2 Automate ⇒ expression régulière
La construction d’une expression régulière à partir d’un automate est un peu plus
délicate, nous allons la diviser en deux étapes, lors d’une première étape, l’automate
est transformé en un automate d’un autre type, appelé automate fini généralisé (ou
tout simplement automate généralisé). Cet automate est transformé en expression
régulière lors d’une seconde étape.

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

Fig. 2.11 – Un automate généralisé

Il est facile de construire un automate généralisé à partir d’un automate, il suffit


pour cela d’ajouter un nouvel état initial possèdant une transition-ε vers l’ancien
état initial et un nouvel état d’acceptation vers lequel il existe une transition-ε
partant des anciens états d’acceptation. S’il existe plusieurs transitions entre deux
états, elles sont remplacées par une transition unique étiquetée par l’union des
étiquettes des différentes transitions. Finalement, des transitions étiquetées ∅ sont
ajoutées entre les états qui ne sont reliés par aucune transition. Cet ajout ne mo-
difie pas le langage reconnu par l’automate car une transition étiquetée ∅ ne peut
jamais être franchie. L’automate généralisé correspondant à l’automate de la fi-
gure 2.1 est représenté dans la figure 2.12.

Il reste maintenant à construire une expression réguilère à partir d’un automate


généralisé. Cette construction s’effectue de manière itérative en diminuant d’un,
à chaque itération, le nombre d’états de l’automate généralisé. A l’issue de cette
étape, on obtient un automate généralisé comportant deux états (l’état initial
1 0

0
ε ε
I A B F

Fig. 2.12 – Transformation d’un automate en automate généralisé

et l’état d’acceptation) et une transition entre les deux. L’expression régulière


étiquetant cette transition dénote le langage de l’automate initial.

Il nous reste à décrire l’étape de réduction de l’automate généralisé qui consiste


donc à transformer un automate généralisé G comportant k états (avec k > 2)
en un automate G′ comportant k − 1 états. Le principe consiste à choisir un
état de G, que nous appellerons qe à l’éliminer et à “réarranger” le reste des
transitions de façon à ce que G et G′ reconnaissent le même langage. Le principe
du réarrangement est le suivant : s’il existe dans G une transition de l’état q1
vers l’état qe étiquetée R1 et une transition de qe vers lui-même étiqueté R2 et
finalement une transition de qe vers q2 étiquetée R3 , alors on crée une nouvelle
transition, allant de q1 vers q2 étiquetée avec l’expression régulière suivante :

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

Fig. 2.13 – Elimination d’un état d’un automate généralisé

L’application de cette méthode à l’automate de la figure 2.12 est représentée dans


la figure 2.14. Dans un premier temps l’état A est éliminé et dans un second
temps l’état B. L’expression régulière résultante est 1∗ 0(0 + 11∗ 0)∗ que l’on peut
transformer en 1∗ 0((ε + 11∗ )0)∗ puis en 1∗ 0(1∗ 0)∗ qui est équivalente à l’expression
régulière (1 + 0)∗ 0.
0+11*0

1*0 ε
I A F

1*0(0+11*0)*
I F

Fig. 2.14 – Elimination des états A et B


Chapitre 3

Langages hors contexte

3.1 Grammaires hors-contexte


Les grammaires hors contexte sont très utilisées pour décrire la syntaxe des lan-
gages, et en particulier des langages de programmation. En plus de définir un
langage, une grammaire hors contexte G permet d’attribuer une strucuture syn-
taxique. aux mots de L(G).
Soit la grammaire G1 des expressions arithmétiques :

G1 = h{E, T, F }, {a, +, −, ∗(, )}, P, Ei avec P = {E → T +E | T , T → F ∗T | F , F → (E) | a}

3.1.1 Sens de dérivation


Les proto-phrases générées lors d’une dérivation utilisant des règles hors-contexte,
peuvent comporter plus d’un symbole non terminal1 , comme le montre la dérivation
suivante du mot a + a ∗ a par la grammaire G1 2 .

E ⇒ T +E ⇒ T +T ⇒ F +T ⇒ F +F ∗T ⇒ F +a∗T ⇒ F +a∗F ⇒ a+a∗F ⇒ a+a∗a


Selon le symbole non terminal que l’on décide de réécrire à un moment donné
de la dérivation, des dérivations différentes sont obtenues. Des dérivations qui ne
diffèrent que par l’odre dans lequel est appliqué les règles de réécriture sont dites
équivalentes. Parmi toutes les dérivations équivalentes d’un même mot par une
grammaire, nous allons en distinguer deux appelées dérivation droite et dérivation
gauche. Dans une dérivation droite (respectivement gauche), à chaque étape de la
dérivation, c’est le non terminal le plus à droite (respectivement le plus à gauche)
de la proto-phrase qui est réécrit. La dérivation gauche du mot a + a ∗ a par G1
est représentée ci-dessous :

E ⇒ T +E ⇒ F +E ⇒ a+E ⇒ a+T ⇒ a+F ∗T ⇒ a+a∗T ⇒ a+a∗F ⇒ a+a∗a


Et voici la dérivation droite :

E ⇒ T +E ⇒ T +T ⇒ T +F ∗T ⇒ T +F ∗F ⇒ T +F ∗a ⇒ T +a∗a ⇒ F +a∗a ⇒ a+a∗a


1
On pourra remarque que ce n’était pas le cas pour les grammaires régulières.
2
Le symbole qui est réécrit dans chaque proto-phrase a été souligné.

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.

Etant donné une grammaire G = hN, Σ, P, Si, un arbre de dérivation pour G


est un arbre ordonné et étiqueté dont les étiquettes appartiennent à l’ensemble
N ∪ Σ ∪ {ε}. Si un nœud de l’arbre est étiqueté par le non terminal A et ses fils
sont étiquetés X1 , X2 , ..., Xn alors la règle A → X1 , X2 , ..., Xn appartient à P .

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.

L’arbre syntaxique correspondant au mot a + a ∗ a est représenté ci-dessous.


E
HH
 HH
T + E

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

G2 = h{E}, {a}, {E → E + E | E ∗ E | a}, Ei


par exemple, est ambiguë, elle permet d’attribuer au mot a + a ∗ a les deux arbres
ci-dessous :

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.

3.2 Transformation de grammaires


Contrairement aux règles régulières qui sont très contraintes, les règles hors-contexte
peuvent, elles, prendre un très grand nombre de formes. Certains algorithmes
prenant en entrée des grammaires hors-contexte imposent que ces derinères se
présentent sous une forme particulière. Nous décrirons ci-dessous trois types im-
portants de formes que sont la forme normale de Chomsky, les grammaires non
récursives à gauche et les grammaires factorisées à gauche ainsi que des méthodes
permettant de transformer une grammaire quelconque en une grammaire équivalente
conforme à chacune de ces différentes formes. Avant cela, nous décrirons quelques
caractéristiques que peuvent vérifier des grammaires hors-contexte.

– le symbole non terminal X d’une grammaire G = hN, Σ, P, Si est dit inutile si


l’on ne peut dériver un mot sur Σ à partir de X :
+
X ∈ N inutile ⇔ {m ∈ Σ∗ | X ⇒ m} = ∅
Toute grammaire comportant des symboles inutiles peut être transformée en une
grammaire équivalente ne comportant pas de symboles inutiles.

– le symbole non terminal X d’une grammaire G = hN, Σ, P, Si est dit inaccessible


s’il n’apparaı̂t dans aucune proto-phrase de la grammaire.

+
X ∈ N inaccessible ⇔ {m = αXβ , α, β ∈ (Σ ∪ N)∗ | S ⇒ m} = ∅

Toute grammaire comportant des symboles inaccessibles peut être transformée


en une grammaire équivalente ne comportant pas de symboles inaccessibles.

– Une règle-ε est une règle de la forme A → ε. Une grammaire G = hN, Σ, P, Si


est dite sans règles-ε si :
1. P ne possède pas de règle-ε, ou
2. P possède une seule règle-ε : S → ε et S n’apparaı̂t dans la partie droite
d’aucune règle de P .

– 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.

3.2.1 Forme normale de Chomsky


Une grammaire hors-contexte est en forme normale de Chomsky si toutes ses règles
sont de la forme :

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.

Conversion en forme normale de Chomsky


La conversion d’une grammaire s’effectue en plusieurs étapes. A chaque étape,
des règles qui ne sont pas en forme normale sont remplacées par d’autres règles
qui le sont. On commence par remplacer l’axiome S par un nouveau symbole non
terminal, puis on élimine les règles de la forme A → ε puis les règles de la forme
A → B. Dans les deux cas, les autres règles de la grammaire sont transformées
de façon à ne pas modifier le langage généré. Pour finir, les règles restantes sont
transformées. Tout cela est décrit plus précisément ci-dessous.
Entrée : Une grammaire hors contexte G = hN, Σ, P, Si
Sortie : Une grammaire équivalente à G en forme normale de Chomsky
Méthode :

1. Création d’un nouvel axiome. On crée un nouveau symbole S0 et on ajoute la


règle S0 → S. Cette modification garantit que l’axiome n’apparaı̂t pas dans
une partie droite de règle.
2. Elimination des règles-ε. On élimine une règle de la forme A → ε ∈ P , pour
A 6= S0 puis, pour toute occurrence de A dans une règle de P , on ajoute une
nouvelle règle dans laquelle cette occurrence de A a été éliminée. La règle
X → αAβAγ, par exemple, provoquera l’ajout des trois règles suivantes :
X → αβAγ, X → αAβγ et X → αβγ. Si X → A ∈ P alors on ajoute
X → ε à moins que cette dernière n’ait déjà été éliminée. On recommence
cette étape tant que P possède des règles-ε.
3. Elimination des règles A → B. On élimine une règle de la forme A → B.
Pour toute règle de la forme B → α, on ajoute une règle A → α à moins
qu’il ne s’agisse d’une règle déjà éliminée. On recommence cette étape tant
que P possède des règles de la forme A → B.
4. Transformation des règles restantes. Toute règle de la forme A → α1 α2 . . . αk
avec k ≥ 3 et αi ∈ Σ∪N, est remplacée par les règles A → α1 A1 , A1 → α2 A2 ,
. . ., Ak−2 → αk−1αk où A1 . . . Ak sont de nouveaux non terminaux. Si k ≥ 2,
on remplace tout symbole terminal αi des règles précédentes par un nouveau
symbole non terminal Ui et on ajoute la règle Ui → αi

Exemple :

1. Création d’un nouvel axiome.


S0 → S
S → ASA|aB
S → ASA|aB
A → B|S
A → B|S
B → b|ε
B → b|ε

2. Elimination des règles-ε.


S0 → S S0 → S
S → ASA|aB|a S → ASA|aB|a|SA|AS|S
A → B|S|ε A → B|S
B→b B→b
3. Elimination des règles A → B.

Elimination de S → S à gauche et de S0 → S à droite :

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).

On distingue deux cas de récursivité gauche, la récursivité gauche directe et la


récursivité gauche indirecte. Dans le permier cas, la récursivité à gauche apparaı̂t à
l’issue d’une seule dérivation. Par exemple lors de l’application de la règle A → AB
au symbole A :A ⇒ AB. Dans le second cas, la récursivité à gauche apparaı̂t après
plusieurs dérivations. Par exemple lors de l’application sucessive des deux règles
A → BC et B → AE à A : A ⇒ BC ⇒ AEC.

Certains algorithmes d’analyse, et en particulier les algorithmes d’analyse des-


cendante décrits en 3.5, ne fonctionnent qu’avec des grammaires non récursive à
gauche. Cette condition est en fait peu contraignante car :

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.

Elimination de la récursivité à gauche directe


Soit G = hN, Σ, P, Si une grammaire hors contexte, et soit

A → Aα1 | Aα2 | . . . | Aαm | β1 | β2 | . . . | βn


toutes les règle de P ayant A pour partie gauche.

G génère le même langage que la grammaire G′ définie de la façon suivante :

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

Cette méthode permet d’éliminer la récursivité à gauche directe, mais ne garantit


pas la non récursivité à gauche indirecte. Pour cela, on recourt à la méthode sui-
vante.

Elimination de la récursivité à gauche


Le principe consiste à éliminer la récursivité à gauche de façon incrémentale,
en considérant des ensembles de règles de plus en plus important, jusqu’à avoir
traité toute les règles. Pour cela on ordonne les non terminaux de la grammaire :
A1 , . . . , An et on commence par éliminer la récursivité directe des règles de la forme
A1 → α. Puis on traite les règles de la forme A2 → β et ainsi de suite, jusqu’à
avoir transformé toute la grammaire. L’algorithme est décrit ci-dessous :

Entrée : une grammaire propre G = hN, Σ, P, Si


Sortie : une grammaire G′ non récursive à gauche

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.

On commence par éliminer la récursivité directe sur A puis on remplace dans B →


CA | Ab A par BC | a puis on élimine la récursivité directe sur B. On remplace alors
dans C → AB | CC | a A par BC | a, ce qui donne C → BCB | aB | CC | a. Puis
on remplace B par CA | ab | CAB ′ | abB ′ et on termine en éliminant la récursivité
directe sur C. Ces différentes étapes sont détaillées ci-dessous :

i=1 pas de changements


i = 2 j = 1 B → CA | BCb | ab
i=2 B → CA | ab | CAB ′ | abB ′
B ′ → CbB ′ | Cb
i = 3 j = 1 C → BCB | aB | CC | a
i = 3 j = 2 C → CACB | abCB | CAB ′ CB | abB ′ B | aB | CC | a
i=3 C → abCB | abB ′ CB | aB | a | abCBC ′ | abB ′ BC ′ | aBC ′ | aC ′
C ′ → ACBC ′ | AB ′ CBC ′ | CC ′ | ACB | AB ′ B | C

3.2.3 Factorisation à gauche


Une grammaire G est dite factorisée à gauche si les parties droites de deux règles
ayant la même partie gauche n’ont pas de prefixe commun propre : (A → αβ1 | αβ2
avec α 6= ε).

Entrée : une grammaire G

Sortie : une grammaire équivalente factorisée à gauche

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 → αβ1 | αβ2 | . . . | αβn | γ


où γ représente toutes les parties droites qui ne commencent pas par α, par :

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

3.3 Automate à pile


Un automate à pile possède les différents éléments d’un reconnaisseur, sa particu-
larité est son mode de stockage : une pile dans laquelle sont stockés des symboles
d’un alphabet particulier appelé alphabet de pile. De plus, à l’instar d’un auto-
mate à états finis, la tête de lecture d’un automate à pile ne peut se déplacer que
d’une case à chaque mouvement du reconnaisseur, de la gauche vers la droite. Ces
différents éléments sont représentés dans la figure 3.1.
Un automate à pile peut stocker des symboles dans sa pile, pour les relire en-
suite. L’automate ne peut lire que le symbole se trouvant au sommet de la pile
(dépiler) et ne peut ajouter un symbole (empiler) qu’en sommet de pile. C’est
la présence de la pile qui permet à l’automate de reconnaı̂tre certains langages
non-réguliers. Un automate à pile peut reconnaı̂tre le langage an bn par exemple,
TETE DE LECTURE

BANDE DE LECTURE

UNITE DE CONTROLE PILE

Fig. 3.1 – Eléments d’un automate à pile

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.

Un automate à pile effectue un mouvement en fonction de son état courant, du


symbole se trouvant sous la tête de lecture et du symbole se trouvant au sommet
de la pile. Le mouvement consiste à déplacer la tête de lecture, à changer d’état,
à dépiler un symbole de la pile et à empiler un ou plusieurs symboles.

Plus formellement, un automate à pile est un septuplet hQ, Σ, Γ, δ, q0 , Z0 , F i


– Q est l’ensemble des états
– Σ est l’alphabet d’entrée
– Γ est l’alphabet de symboles de pile
– δ est la fonction de transition

δ : Q × (Σ ∪ {ε}) × Γ → ℘(Q × Γ∗ )

– q0 ∈ Q est l’état initial


– Z0 ∈ Γ est le symbole de fond de pile, qui se trouve initialement dans la pile
(voir 3.3.2)
– F ⊆ Q est l’ensemble des états d’acceptation

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 :

(q, aw, Zα) ⊢ (q ′ , w, γα)


si δ(q, a, Z) contient le couple (q ′ , γ).
Lors de ce mouvement :
– l’automate est passé de l’état q à l’état q ′ ,
– le symbole a a été lu,
– la tête de lecture s’est déplacée d’une case vers la droite,
– le symbole Z a été dépilé et le mot γ empilé.
Remarques :
– Si γ = ε, on dit que la pile a été dépilée.

– Si a = ε, aucun symbole n’a été lu sur la bande de lecture et la tête de lecture


n’a pas été déplacée. Par contre, l’état de l’automate peut avoir changé, ainsi
que le contenu de la pile.

3.3.1 Représentation graphique d’un automate à pile


On peut représenter un automate à pile sous la forme d’un graphe, comme dans
le cas des automates finis. La différence entre les deux représentations concerne
la gestion de la pile : les opérations d’empilement et de dépilement. Elles sont
indiquées en étiquetant les transitions d’étiquettes de la forme a, b → c. Une telle
étiquette sur un arc allant de qi à qj signifie que l’automate franchit cet arc en lisant
a et en remplaçant b par c sur le sommet de la pile. Ce qui dans la représentation
formelle correspond à : δ(qi , a, b) = {(qj , c)}.
– si a = ε, l’automate peut franchir cet arc sans lire de symbole.
– si b = ε, l’automate peut franchir cet arc indépendamment du symbole se trou-
vant en sommet de pile.
– si c = ε, l’automate peut franchir cet arc sans rien empiler.
Exemple 1 : A1 = h{q0 , q1 , q2 }, {a, b}, {Z, a}, δ, q0, Z, {q2}i avec :

δ(q0 , a, Z) = {(q1 , aZ)}


δ(q1 , a, a) = {(q1 , aa)}
δ(q1 , b, a) = {(q2 , ε)}
δ(q2 , b, a) = {(q2 , ε)}

A1 (voir figure 3.2) est un automate déterministe qui reconnaı̂t le langage an bn . A1


commence par lire une séquence de a tout en les empilant dans la pile puis dépile
un a pour tout b lu.

a, a −> aa b, a −> ε

q0 q1 q2
a, Z −>aZ b, a −> ε

Fig. 3.2 – Automate à pile reconnaissant le langage an bn


Exemple 2 : A2 = h{B, C, D, E, F }, {a, b, c}, {$, a}, δ, B, $, {D, F }i avec :

δ(B, a, ε) = {(B, a)} δ(C, b, a) = {(C, ε)}


δ(B, ε, ε) = {(C, a), (E, ε)} δ(C, ε, $) = {(D, $)}
δ(D, c, $) = {(D, $)}

δ(E, b, ε) = {(E, ε)}


δ(E, ε, ε) = {(F, ε)}
δ(F, c, a) = {(F, ε)}

A2 (voir figure 3.3) est un automate non-déterministe qui reconnaı̂t le langage


L = {ai bj ck | i, j, k ≥ 0 et i = j ou i = k} A1 commence par lire une séquence de a
tout en les empilant pour pouvoir ensuite comparer leur nombre avec le nombre de
b ou le nombre de c. Cette deuxième étape est un peu délicate et c’est là qu’entre
en jeu le non-déterminisme. Chaque branche de l’automate correspond à une des
alternatives i = j ou i = k. Dans la branche supérieure, A2 vérifie que le nombre
de b est égal au nombre de a tandis que dans la branche inférieure, il vérifie que
le nombre de b est égal au nombre de a.

b , a ε

C D c ,$ $

ε, ε ε ε, ε ε

ε, ε ε ε, ε ε
B E F c , a ε

a ,ε a b ,ε ε

Fig. 3.3 – Automate à pile reconnaissant le langage ai bj ck avec i = j ou i = k

3.3.2 Reconnaissance d’un mot par un automate non déterministe


Une configuration initiale d’un automate à pile A = hQ, Σ, Γ, δ, q0 , Z0 , F i est une
configuration de la forme (q0 , m, Z0) avec m ∈ Σ∗ . En d’autres termes, A se trouve
dans l’état initial, la tête de lecture se trouve sur le premier symbole du mot à
reconnaı̂tre et la pile ne contient que le symbole de fond de pile.

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, $)

(B, abcc, a$)

(B, bcc, aa$)


H
 HH
 H
(C, bcc, aa$) (E, bcc, aa$)

(C, cc, a$) (E, cc, aa$)

(D, cc, a$) (F, c, a$)

(F, ε, $)

3.4 Automate à pile ⇔ Grammaires hors-contexte


Les automates à pile constituent des reconnaisseurs pour langages hors contexte.
Pour pouvoir affirmer cela, il faut démontrer que tout langage reconnu par un
automate à pile peut être généré par une grammaire hors contexte et que, inver-
sement, tout langage généré par une grammaire hors contexte peut être reconnu
par un automate à pile. Nous montrerons ici uniquement comment construire un
automate à pile à partir d’une grammaire.

P ⊂ Σ∗ est un langage hors-contexte si et seulement si P est reconnu par un


automate à pile.

3.4.1 Grammaires hors-contexte ⇒ Automate à pile


Soit G = hN, Σ, P, Si une grammaire hors-contexte, on construit un automate à
+
pile A qui accepte un mot m s’il existe une dérivation pour m dans G (S ⇒ m).
A est conçu de telle sorte à déterminer une dérivation conduisant de S à m.

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 ε

Fig. 3.4 – Différents états de la pile lors de la reconnaissance du mot a + a ∗ 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.

L’automate à pile A correspondant à la grammaire G = hN, Σ, P, Si non récursive


à gauche est défini de la façon suivante :

A = h{q0 , q1 , q2 }, Σ, N ∪ Σ ∪ {Z0 }, δ, q0 , Z0 , {q2 }i

– A possède trois états : {q0 , q1 , q2 }.


– l’alphabet d’entrée est l’alphabet terminal de G.
– l’alphabet de pile est constitué des symboles non terminaux de G de l’alphabet
terminal Σet du symbole de fond de pile Z0 .
– la fonction de transition δ est définie de la façon suivante :
– δ(q0 , ε, Z0) = {(q1 , SZ0)} On empile l’axiome.
– δ(q1 , ε, Ni) = {(q1 , mi ) | avec Ni → mi ∈ P }
Si un symbole non terminal Ni occupe le sommet de la pile, on le remplace
par la partie droite mi d’une règle Ni → mi .
– δ(q1 , a, a) = {(q1 , ε) | avec a ∈ Σ}
Si le même symbole terminal occupe le sommet de la pile et la case courante
de la bande d’entrée, on dépile.
– δ(q1 , ε, Z0) = {(q2 , Z0 )}
Si le mot en entrée a été reconnu et que la pile ne contient que le symbole de
fond de pile, on passe à l’état d’acceptation.
– q0 est l’état initial.
– Z0 est le symbole de fond de pile.
– q2 est l’unique état d’acceptation.
Cet automate est représenté sous sa forme graphique dans la figure 3.5.

ε, Ni −> m pour toute règle Ni −> m de P


a, a −> ε pour tout terminal a de Σ

q0 q1 q2
ε, ε −> S ε, Z0 −> Z0

Fig. 3.5 – Automate correspondant à la grammaire G = hN, Σ, P, Si

Exemple :
L’automate à pile A1 correspondant à la grammaire G1 est défini de la façon
suivante :

A1 = h{q0 , q1 , q2 }, {a, +, ∗, (, )}, {E, T, F, Z0}, δ, q0 , Z0 , {q2 }i


avec :

δ(q0 , ε, Z0) = {(q1 , EZ0 , ε)} δ(q1 , +, +) = {(q1 , ε)}


δ(q1 , ε, E) = {(q1 , E + T ), (q1 , T )} δ(q1 , ∗, ∗) = {(q1 , ε)}
δ(q1 , ε, T ) = {(q1 , T ∗ F ), (q1 , F )} δ(q1 , (, () = {(q1 , ε)}
δ(q1 , ε, F ) = {(q1 , (E)), (q1 , a)} δ(q1 , a, a) = {(q1 , ε)}
δ(q1 , ε, Z0) = {(q2 , Z0 )}

3.5 Analyse syntaxique


Etant donné une grammaire hors-contexte G, on dit qu’un mot m ∈ L(G) a été
analysé lorsque l’on connaı̂t un (ou tous ses) arbres de dérivations. Un analyseur
syntaxique pour une grammaire G est donc une machine qui prend en entrée un
mot m et produit un (ou tous) les arbres de dérivations de m.

3.5.1 Transducteurs à pile


Nous allons définir un autre type d’automate, appelé transducteur à pile qui sont
très proches des automates à pile définis ci-dessus. La différence entre ces deux
types de machines réside dans le fait qu’un transducteur possède en plus d’une
bande d’entrée une bande de sortie sur laquelle il peut écrire grâce à une tête
d’écriture. A chaque mouvement du transducteur, un mot sur un alphabet de sor-
tie peut être écrit sur la bande de sortie. Les différents éléments d’un transducteur
à pile sont représentés dans la figure 3.6.

Formellement, un transducteur à pile est un 8-uplet hQ, Σ, Γ, ∆, δ, q0 , Z0 , F i défini


de la façon suivante :
– Q est l’ensemble des états
– Σ est l’alphabet d’entrée
TETE DE LECTURE

BANDE D’ENTREE

UNITE DE CONTROLE
PILE

BANDE DE SORTIE

TETE D’ECRITURE

Fig. 3.6 – Eléments d’un transducteur à pile

– Γ est l’alphabet de symboles de pile


– ∆ est l’alphabet de sortie
– δ est la fonction de transition

δ : Q × (Σ ∪ {ε}) × Γ → ℘(Q × Γ∗ × ∆∗ )

– q0 ∈ Q est l’état initial


– Z0 ∈ Γ est le symbole de fond de pile
– F ⊆ Q est l’ensemble des états d’acceptation
Une configuration d’un transducteur à pile est un quadruplet (q, m, α, y) 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.
– α représente le contenu de la pile. Le symbole le plus à gauche est le sommet de
la pile.
– y est la séquence de symboles de sortie produite.

3.5.2 Analyseurs gauches


Un analyseur gauche pour une grammaire G est un transducteur à pile qui pro-
duit en sortie une dérivation gauche du mot présent sur sa bande d’entrée. Cette
dérivation est représentée par une suite de chiffres, chaque chiffre correspondant à
une règle de G, ces dernières ayant été préalablement numérotées.

Soit la grammaire des expressions arithmétique G1 = h{E, T, F }, {a}, P, Ei dont


on a numéroté les règles :

1 E →T +E 2E→T
3 T →F ∗T 4T →F
5 F → (E) 6F →a

La dérivation gauche du mot a+a∗a se présente maintenant sous la forme suivante :

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.

Un tel transducteur peut être construit immédiatement à partir d’une grammaire


hors-contexte G en suivant le principe de la section 3.4.1. La seule différence étant
que, pour le transducteur, la fonction de transition indique le numéro de la règle
correspondant à la transition.

Exemple : L’analyseur gauche T1g correspondant à la grammaire G1 est défini de


la façon suivante :

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)

3.6 Analyse descendante


Etant donné une grammaire G il est possible de construire un analyseur gauche TGg
et d’effectuer l’analyse d’un mot m en simulant le fonctionnement de TGg sur l’entrée
m. Ce type d’analyse est dit descendant car il consiste à construire un arbre de
dérivation de m à partir de sa racine (l’axiome). La difficulté de ce type d’analyse
provient du fait que TGg est en général non déterministe, il faut par conséquent
gérer ce non-déterminisme, comme le décrit la section 3.6.1. Dans certains cas TGg
peut être rendu déterministe, comme nous le verrons dans la section 3.6.2.

3.6.1 Analyseur récursif


Soit un analyseur gauche non-déterministe TGg , et un mot m. L’ensemble des
séquences différentes de mouvements que TGg peut décrire sur l’entrée m étant
fini4 , une façon un peu brutale de simuler de façon déterministe TGg consiste à
les construire toutes, dans un certain ordre. C’est l’idée sous-jacente à l’analyse
récursive.

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.

Considérons la grammaire G = h{S}, {a, b, c}, P, Si avec les production suivantes :

1 S → aSbS 2 S → aS 3 S → c

et l’analyseur gauche TGg de G défini de la façon suivante :

TGg = h{q0 , q1 , q2 }, {a, b, c}, {S, Z0}, {1, 2, 3}, δ, q0, Z0 , {q2 }i

δ(q0 , ε, Z0 ) = {(q1 , SZ0 , ε)}


δ(q1 , a, S) = {(q1 , SbS, 1), (q1 , S, 2)}
δ(q1 , c, S) = {(q1 , ε, 3)}
δ(q1 , b, b) = {(q1 , ε, ε)}
δ(q1 , ε, Z0 ) = {(q2 , Z0 , ε)}

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 , ε)

C0 (q1 , aacbc, SZ0 , ε)


HH
 HH
 HH
 H
 HH
 HH
 HH
C1 (q1 , acbc, SbSZ0 , 1) C2 (q1 , acbc, SZ0 , 2)
H H
 HH  HH
 HH
 HH


HH
 HH 
C3 (q1 , cbc, SbSbSZ0 , 11) C4 (q1 , cbc, SbSZ0 , 12) C11 (q1 , cbc, SbSZ0 , 21) C15 (q1 , cbc, SZ0 , 22)

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)

A partir de C−1 un seul mouvement est possible, menant en C0 . A partir de C0


deux mouvements sont possibles, vers C1 et C2 , correspondant respectivement au
choix de la règle 1 ou 2 pour réecrire S. En C1 , le sommet de la pile est encore oc-
cupé par S, et donc deux possibilités s’offrent pour réecrire ce dernier, aboutissant
aux deux configurations C3 et C4 . A partir de chacune de ces deux configurations,
un seul chemin mène respectivement à C7 et C10 . A partir de C2 deux mouvements
sont possibles, menant en C11 et C15 d’où on peut rejoindre les deux configurations
C14 et C16 .

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.

La première branche parcourue est donc : C0 , C1 , C3 , C5 , C6 , C7 , elle ne constitue


pas une analyse de aacbc car C7 n’est pas un état d’acceptation. Pour déterminer
s’il existe une autre analyse possible on remonte dans l’arbre jusqu’à aboutir à
un nœud dont un fils n’a pas été parcouru. Pour cela, on exécute “à l’envers”
les mouvements qui ont mené l’analyseur en C7 jusqu’à revenir à la configuration
C1 , à partir de laquelle on atteint en quatre mouvements l’état C10 qui est un
état d’acceptation, correspondant à l’analyse gauche : 1233. Si l’objectif est de
déterminer toutes les analyses gauches du mot (dans le cas où la grammaire est
ambiguë) alors on continue le parcours de l’arbre, ce qui permettra de déterminer
une seconde analyse gauche : 2133 représentée par l’état C14 .

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

Fig. 3.7 – Eléments d’un analyseur LL

Une configuration d’un analyseur LL est un triplet (au, Xα, π) où :


1. au représente la partie du mot d’entrée non encore lue, a est le symbole
terminal se trouvant sous la tête de lecture.
2. Xα représente le contenu de la pile (avec X au sommet de cette dernière)
3. π représente le mot produit sur la bande de sortie.
Si m ∈ Σ∗ est le mot à analyser, la configuration initiale de l’analyseur est :
(m$, S$, ε) $ étant le symbole de fond de pile qui sert aussi à marquer la fin de
la chaı̂ne à analyser. Une configuration d’acceptation se présente sous la forme :
($, $, π) π étant l’analyse gauche de m.

L’analyseur LL effectue une analyse en décrivant une séquence de mouvements


qui ressemblent aux mouvements d’un transducteur à pile. Le mouvement à effec-
tuer à partir d’une configuration (au, Xα, π) dépend de a et de X. Trois cas sont
possibles :
1. Si X = a = $, l’analyseur s’arrête et annonce le succès de l’analyse.
2. Si X = a 6= $, l’analyseur enlève X de la pile et avance la tête de lecture :

(au, aα, π) ⊢ (u, α, π)


3. Si X est un symbole non terminal, l’analyseur consulte l’entrée M(X, a) de
la table d’analyse M. Deux cas sont possibles :
(a) M(X, a) = i où i est le numéro d’une règle ayant X pour partie gauche
(X → β). Dans ce cas, X est dépilé, β est empilé et i est écrit sur la
bande de sortie.

(au, Xα, π) ⊢ (au, βα, πi)


(b) M(X, a) = erreur, l’analyse s’arrête et annonce l’échec de l’analyse.

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

Soit la table d’analyse LL correspondant à G :

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

L’analyse du mot (a ∗ a) correspond aux mouvements suivants :

((a ∗ a), E$, ε) ⊢ ((a ∗ a), T E ′ $, 1)


⊢ ((a ∗ a), F T ′ E ′ $, 14)
⊢ ((a ∗ a), (E)T ′ E ′ $, 147)
⊢ (a ∗ a), E)T ′ E ′ $, 147)
⊢ (a ∗ a), T E ′ )T ′ E ′ $, 1471)
⊢ (a ∗ a), F T ′ E ′ )T ′ E ′ $, 14714)
⊢ (a ∗ a), aT ′ E ′ )T ′ E ′ $, 147148)
⊢ (∗a), T ′ E ′ )T ′ E ′ $, 147148)
⊢ (∗a), ∗F T ′E ′ )T ′ E ′ $, 1471485)
⊢ (a), F T ′ E ′ )T ′ E ′ $, 1471485)
⊢ (a), aT ′ E ′ )T ′ E ′ $, 14714858)
⊢ (), T ′ E ′ )T ′ E ′ $, 14714858)
⊢ (), E ′ )T ′ E ′ $, 147148586)
⊢ (), )T ′ E ′ $, 1471485863)
⊢ (ε, T ′ E ′ $, 1471485863)
⊢ (ε, E ′ $, 14714858636)
⊢ (ε, $, 147148586363)

Construction d’une table LL(1) à partir d’une grammaire


La construction d’une table d’analyse LL(1) pour une grammaire G = hN, Σ, P, Si
est facilitée par les deux fonctions premier et suivant. Ces deux fonctions pe-
mettent, quand c’est possible de remplir les entrées de la table d’analyse LL(1) de
G.

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 ) = {+, ∗, ), $}

Construction de la table LL(1)


Entrée : G = hN, Σ, P, Si Une grammaire dont les règles sont numérotées.
Sortie : M Une table d’analyse LL(1) pour G.

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

Dérivation, 8 Opérations régulières, 16


droite, 37 priorités, 16
gauche, 37 Partie droite d’une règle, 7
Déterminisme, 12, 23 Partie gauche d’une règle, 7
Prefixe, 6
Ensemble régulier, 15
Proto-phrase, 8
Etat
accessible, 21 Règle
co-accessible, 21 simple, 40
d’acceptation d’un automate, 21 Règle-ε, 39
d’un reconnaisseur, 11 Règles
initial d’un automate, 21 de production, 7
puits, 22 de réécriture, 7
Expression régulière, 15 Reconnaisseur, 11
Fermeture de Kleene, 7 Structure syntaxique, 37
Forme normale Suffixe, 6

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

S-ar putea să vă placă și