Académique Documents
Professionnel Documents
Culture Documents
1. Définition
Une grammaire formelle est un quadruplet G=<VN, VT, S P> où:
– VN est un ensemble fini non vide de symboles dit alphabet non terminal.
– VT est un ensemble fini non vide de symboles dit alphabet terminal, dont les éléments sont
appelés symboles terminaux et sont ici par convention en lettres minuscules.
Les alphabets VN et VN sont disjoints, leur union définit l’alphabet global V:
V N ∩V T =∅ V =V N ∪V T
– P est l’ensemble fini et non vide des règles grammaticales, ou productions; chaque
production est de la forme où ∈V * est appelé tête ou membre gauche, et
*
∈V est appelé corps ou membre droit. V* est l’ensemble de toutes les séquences
formées de symboles appartenant au vocabulaire V , y compris la chaîne vide dénotée
ou ^ . La tête contient au moins un symbole non terminal,
– S constitue l’axiome, soit un élément particulier de VN , ou symbole de départ:
*
A ,∈V .
V *=V N ∪V T * et V + =V *−{^}
2. Classification de Chomsky
La définition des grammaires génératives donnée cidessus n’impose aucune contrainte sur
les productions. En introduisant des limitations sur la forme de ces productions, Noam Chomsky a
introduit en 1956 une classification hiérarchique des grammaires et des langages .
D éfinition. Une grammaire est horscontexte (CGF) G=<VN, VT, P, S> si toutes les régles sont
de la forme X avec X ∈V N et ∈V * .
Exemples:
● Le langage des expressions arithmétiques
VN = {exprp,expr, nombres, op,chiffres}
VT = {0,1,2,3,4,5,6,7,8,9,+,*,,/}
P ={ exprp expr expr expr op expr , op ' ' , op ' −' , op '∗' ,
op ' /' , nombres nombres chiffres , chiffres 0 , chiffres 1 ,
chiffres 2 , chiffres 3 , chiffres 4 , chiffres 5 , chiffres 6 ,
chiffres 7 , chiffres 8 , chiffres 9 }
● Une CFG qui engendre le langage {a b | n ≥ 0} :
n n
S → aSb | ^
● Une CFG qui engendre les palindromes sur {a, b} :
les mot de langage sont symétriques, c'est à dire la transposée de chaque mot donne le mot
lui même.
S → aSa | bSb | ^
On voit bien que dans ces exemples, toutes les régles sont de la forme X avec X ∈V N et
*
∈V .
Exemple (dérivation)
<phrase> ⇒ <Sujet> <Verbe> <COD> (1)
⇒ <Sujet> <Verbe> <Article><Nom> (2)
⇒ Je <Verbe> <Article><Nom> (3)
⇒ Je mange <Article><Nom> (4)
⇒ Je mange le <Nom> (5)
⇒ Je mange le pain (6)
On écrit <Phrase> ⇒ Je mange le pain
*
Dans cet exmeple, on a six dérivations pour obtenir 'Je mange le pain'.
D éfinition. G=<VN, VT, P, S> une grammaire horscontexte (CGF) Une forme syntaxique
∈ V∗ est le résultat d'une ou plusieurs dérivation(s) à partir de l'axiome S de G: S ⇒*
Dans l'exemple, les parties droites des dérivations (1) à (6) sont des Formes syntaxiques.
D éfinition. G=<VN, VT, P, S> une grammaire horscontexte (CGF) Une phrase est une
forme syntaxique particulière où ∈ VT∗ : S ⇒*
Une dérivation est gauche si à chaque fois on remplace le symbole non terminal le plus à gauche :
*
S⇒
G
La dérivation dans l'exemple précedant est une dérivation gauche:
*
<Phrase> ⇒ G
Je mange le pain
Une dérivation est droite si à chaque fois on remplace le symbole non terminal le plus à droite:
*
S⇒D
<phrase> ⇒ <Sujet> <Verbe> <COD> (1)
⇒ <Sujet> <Verbe> <Article><Nom> (2)
⇒ <Sujet> <Verbe> <Article> pain (3)
⇒ <Sujet> <Verbe> le pain (4)
⇒ <Sujet> mange le pain (5)
⇒ je mange le pain (6)
*
<Phrase> ⇒ D
Je mange le pain
On général, S ⇒*
On dit que S engendre ou est engendrée par S.
D éfinition. G=<VN, VT, P, S> une grammaire horscontexte (CGF). Le langage engendré par
*
G est l'ensemble de toutes les phrases w possibles : L(G) = {w ∈ VT∗ | S ⇒ w }.
D éfinition. G=<VN, VT, P, S> une grammaire horscontexte (CGF). Un arbre de dérivation
associé à une régle de production X → X1X2...Xn de P est un arbre dont la racine est X et
X1,X2...,Xn sont ses fils.
Si Xi∈ VT c'est une feuille de l'arbre
Si Xi∈ VN c'est un noeud de l'arbre
Exemple: Dans le langage des expressions arithmétiques expr → expr '+' expr a pour arbre
expr
expr expr
+
Un arbre de dérivation pour une formre syntaxique w ∈ V* à partir d’une variable X ∈ VN est donc
un arbre ordonné étiqueté, dont les nœuds internes sont étiquetés par des variables dans VN et les
feuilles par des terminaux (dans VT ) ou pour tout nœud v étiqueté par X ∈ VN , si X1 , . . . , Xn ∈
V sont les étiquettes des enfants v1, . . . , vn de v, alors X → X1X2...Xn est une règle de G. La racine
est étiquetée par X, et w est la frontière de l’arbre.
Le cas particulier où w ∈ VT (phrase), la frontière de l'arbre n'est composée que des feuilles : C'est
l'arbre syntaxique de w.
Exemples grammaires
E + E
a b * c
3.2. Ambiguité
D éfinition. G=<VN, VT, P, S> une grammaire horscontexte (CGF) est ambiguë si elle existe
une phrase w dans le langage engendré par G qui admet au moins deux arbres syntaxiques
distincts.
E E E E
+ *
a b * c a b c
+
(i) (ii)
En terme de dérivations, on a:
On voit bien qu'avec des dérivations différentes , on obtient la même phrase 'a+b*c'. On dit que la
grammaire G est ambiguë.
On peut enlever l'ambiguité d'une grammaire G. Dans notre exemple, il suffit de reconstruire la
grammaire en donnant aux opérateur + et * des priorités différents:
G': S →E
E → F | E '+' F
F → P | F '*' P
P → '(' E ')' | a | b | c
Dans la grammaire G', on ne peut faire l'addition (+) que si on effectue d'abord la produit (*). Ce
dernier est plus prioritaire que l'addition : priorité(*) > prioritré(+).
La phrase a+b*c admet un seul arbre syntaxique: c'est l'arbre cidessus. La grammaire G' est donc
non ambiguë.
● Ensemble des premiers d'une chaine ∈V + (préfixes) : ensemble de symbole terminaux
t∈V T par lequels commence la partie droite ∈V + d'une régle de production X
avec X ∈V N directement ou après plusieurs dérivations. Il noté Prem( ):
Prem() ={ t ∈V T / *
t avec ∈V
*
}
● Ensemble des suivants d'un non terminal A∈V N (suffixes): ensemble de symboles
terminaux t∈V T qui suivent A dans la partie droite d'une dérivation directe ou indirecte
X * A . Il est noté Suiv(A):
T héorème. G=<VN, VT, P, S> une grammaire horscontexte (CGF) avec A∈V N et i ∈V * i=1 .. n
G est LL(1) ⇄ (I) ∀ A→1 | | | n Prem(i) Ո Prem(j) = Ф avec i ǂ^, j ǂ^ , i ǂ j
*
(II) si ∃ j / j ^ Prem(j) Ո Suiv(A) = Ф
Deux conditions sont necessaires, mais ne sont pas suffisantes pour une grammaire G soit LL(1)
C orolaire. G=<VN, VT, P, S> une grammaire horscontexte (CGF) avec A∈V N et i , ∈V * i=1 .. n
G est LL(1) ⇒ (i) { ∀ A→ 1 | | | n doit être transformée en A→ X avec X→ 1 | | | n
(ii) { ∀ A→ A1 | A | | n | doit être transformée en A→ X avec X→ ^| 1 X | | n X }
La condition (i) concerne des régles dites non deterministes et la contion (ii) concerne les régles
récursives à gauche.
Ainsi, pour monter qu'une grammaire G soit LL(1), il faut d'abord transformer toutes les régles de G
de forme (i) et (ii) de lemme et après il faut vérifier les conditions (I) et (II) de thèorème.
Traitant donc un exemple:
VT={'+', '', '*', '/', '(', ')', cstr, idf }
VN={ER, E, F, P} et S=ER
P={ER → E, E → F | E '+' F | E '' F, F → P | P '*' F | P '/' F, P → cstr | idf | '(' E ')' }
Appliquant d'abord le corolaire:
● transformer les régles de la forme (i) A→ 1 | | 3
F → P | P '*' F | P '/' F est de la forme (i) avec = P, 1=^ 2 = '*' F et 3= '/' F . Sa transformée
A→ X avec X→ 1 | | 3 est: F → P SP et SP → ^ | '*' F | ' /' F on a posé X=SP
● transformer les régles de la forme (ii) A→ A1 | A |
E → F | E '+' F | E '' F est de la forme (ii) avec A=E, 1 = '+' F, 2= '' F et = F . Sa transformée
A→ X avec X→ ^ | 1 A| A est: E → F SF et SF → ^ | '+' F SF | ' ' F SF, on a posé X=SF.
Maintenant que les condition necessaires sont vérifiées, il ne reste qu'appliquer le théorème:
Ecrivons la nouvelle grammaire G':
(1) ER → E
(2) E → F SF
(3) SF → ^ | '+' F SF | '' F SF
(4) F → P SP
(5) SP → ^ | '*' P SP | '/' P SP (on a remplacé F par PSP: dans régle (4) F → P SP )
(6) P → cstr | idf | '(' E ')'
● Les régles (1), (2) et (4) ne posent aucun problème puisqu'elles sont de la forme A → ( pas d'alternance | ).
● La régle (3) est de la forme A → 1 | 2 | 3 avec 1 = ^ , 2 ='+' F SF , 3 = '' F SF et A= SF d'où:
2 !=^ alors X = Prem( 2 ) =Prem('+' F SF ) ={ '+' }
3 != ^ alors Y = Prem( 3 ) =Prem( '' F SF ) ={ '' }
1 = ^ alors Z=Suiv(A)=Suiv(SF).
On cherche là où SF apparaît dans les parties droites des régles à l'exception de la régle traitée (3) . la régle (2)
est la seule qui répond à cette condition: (2) E → F SF
Or aucun terminal ne suit directement SF: Z=Suiv(SF)= Suiv(E) (car E → F SF ).
On cherche là où E apparaît dans les parties droites des régles à l'exception de la régle traitée (3). les régles (1)
et (6) répondent à cette condition: (1) ER → E et (6) P → cstr | idf | '(' E ')'
Or aucun terminal ne suit directement E dans (1), mais ')' suit directement E dans (6) donc : Z=Suiv(E)={ ')' }
Finalement on a:
X = Prem('+' F SF ) ={ '+' }
Y = Prem( '' F SF ) ={ '' }
Z= Suiv(SF)={ ')' }
X Ո Y = Փ , X Ո Z = Փ et Y Ո Z = Փ, la régle (3) vérifie les conditions de theorème.
● La régle (5) est de la forme A → 1 | 2 | 3 avec 1 = ^ , 2 ='*' P SP , 3 = '/' P SP et A= SP d'où:
2 != ^ alors X = Prem( 2 ) =Prem('*' F SF ) ={ '*' }
3 != ^ alors Y = Prem( 3 ) =Prem( '/' F SF ) ={ '/' }
1 = ^ alors Z=Suiv(A)=Suiv(SP).
On cherche là où SP apparaît dans les parties droites des régles à l'exception de la régle traitée (5) . la régle (4)
est la seule qui répond à cette condition: (4) F → P SP
Or aucun terminal ne suit directement SP: Z=Suiv(SP)=Suiv(F) (car F → P SP ).
On cherche là où F apparaît dans les parties droites des régles à l'exception de la régle traitée (5). les régles (2)
et (3) répondent à cette condition: (2) E → F SF et (3) SF → ^ | '+' F SF | '' F SF
S'ils exitent des terminaux qui suivent F, çà sera les premiers de SF car SF suit F:
Z=Suiv(SP) = Premier(SF)SF!=^ U Suiv(SF) SF=^ ( si SF=^ alors (2) devient E → F )
Z={' +', '' } U Suiv(E), or Suiv(E) = { ')' } donc Z = { +', '' , ')' }
Finalement on a:
X = Prem('*' P SP ) ={ '*' }
Y = Prem( '/' P SP ) ={ '/' }
Z= Suiv(SP)={ +', '' , ')' }
X Ո Y = Փ , X Ո Z = Փ et Y Ո Z = Փ, la régle (5) vérifie les conditions de theorème.
● La régle (6) est de la forme A → 1 | 2 | 3 avec 1 = cstr , 2 =idf , 3 = '(' E')' et A= P d'où:
1 != ^ alors X = Prem( 1 ) =Prem(cstr ) ={ cstr }
2 != ^ alors Y = Prem( 2 ) =Prem( idf ) ={ idf }
3 != ^ alors Z = Prem( 3 )={ '(' E')' } = { '(' }
X Ո Y = Փ , X Ո Z = Փ et Y Ո Z = Փ, la régle (6) vérifie les conditions de theorème.
Toute les régles de (1) à (6) ont vérifié les conditions de theorème, alors la grammaire G' est LL(1)
Maintenant, que la grammaire est LL(1), on peut la transformer en un programme dans un langage
de programmation évolué en tant qu' analyseur syntaxique en utilisant une méthode dite ''Descente
récursive''.
ER ER→E
E E→F SF E
F SF F→P
P SF P→idf, Lire x (idf) , Lire + F SF
idf SF SF→F SF
F SF
idf + F SF F→P SP P
idf + P SP SF P→cstr , Lire 2, Lire * P SP
idf + cstr SP SF SP→ P SP
idf + cstr * P SP SF P→idf, Lire y P SP
idf + cstr * idf SP SF SP→ ^
idf + cstr * idf SF SF→ ^ (idf) + (cstr) * (idf)
x 2 y
idf + cstr * idf
On voit bien qu' à partir de l'axiome ER on arrive à la phrase ''x+2*y'' après plusieurs
lectures et applications des régles de P. On dit que la phrase est syntaxiquement juste.
L'algorithme d'un analyseur syntaxique descendant est:
1. Soit un algorithe non récursif qui utilise aussi l'automate fini à pile.
2. Soit un algorithme récursif dit ''descente récursive''
Par la suite, on utilise cette dernière.
3.5.1. Descente récursive
La descente récursive fait correspondre à chaque régle X de la grammaire une action
algorithmique, dont l'entête est X et son corps est :
Remarque:
● l'action Traiter(i ) est l'une ou la conbinaison de plusieurs actions de tableau cidessus. Elle
dépend de la structure de i .
● L'action lire(us) est l'anlyseur lexical qui lit une unité lexicale ou syntaxique us à chaque fois
que c'est necessaire. En effet, l' analyseur lexical necessite tout un chapitre. Pour le réaliser,
on utilise les langages régulier en particulier les automates d'états finis (Chapitres 1 et 2).
Exemple: La descente récursive necessite une grammaire LL(1). Prenant l'exemple de paragraphe
précédant en ajoutant le symbole '$' à la fin la régle (1):
(1) ER → E '$'
(2) E → F SF
(3) SF → ^ | '+' F SF | '' F SF
(4) F → P SP
(5) SP → ^ | '*' P SP | '/' P SP
(6) P → cstr | idf | '(' E ')'
/* La régle (1) ER → E */
action ER()
{
E();
si us!='$' alors erreur('' '$' attendu '') fsi
}
/* La régle (2) E → F SF */
action E()
{
F(); SF()
}
/* La régle (3) SF → ^ | '+' F SF | '' F SF */
action SF()
{
si us!=')' et us!='$' alors /* us != Suiv(SF) */
selon us faire
'+' : lire(us); F(); SF();
'' : lire(us); F(); SF();
autre: erreur('' + ou – attendu'')
fselon
fsi
}
/* La régle (4) F → P SP */
action F()
{
P(); SP()
}
/* La régle (5) SP→ ^ | '*' P SP | '/' P SP */
action SP()
{
si us!=')' et us!='$' et us!='+' et us!='' alors /* us != Suiv(SP) */
selon us faire
'*' : lire(us); P(); SP();
'/' : lire(us); P(); SP();
autre: erreur('' * ou / attendu'')
fselon
fsi
}
/* La régle (6) P → cstr | idf | '(' E ')' */
action P()
{
selon us faire
idf : lire(us);
cstr : lire(us);
'(' : lire(us);
E();
si us =')' alors
lire(us)
sinon
erreur('' ')' attendue'')
fsi
autre: erreur('' idf, cstr ou '(' attendu'')
fselon
}
L'analyseur syntaxique necessite une action principale qui fait appel à l'axiome de la grammaires:
AnalyseurSyntaxique()
{
lire(us); /* lire la première unité syntaxique us */
ER(); /* appel de l'axiome ER */
}
Voici un exemple de la phrase '' x + 2 * 3 $ '' executée par l'analyseur
Remarque:
● Un terminal t souligné : c'est l'unite syntaxique us lue actuelement.
● Un non terminal A() souligné: c'est l'action en execution actuellement .
● Un non terminal A() non souligné: c'est l'action en attente de l'execution prochenement.
Voici un autre exemple d'une phrase erronée '' * 3 $ '' executée par l'analyseur