Vous êtes sur la page 1sur 11

   Ch. 3.

Grammaires ‫ ك‬ ‫ض‬

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 ci­dessus 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 .

Les quatre types hiérarchiques de Chomsky sont:

● Le type 0 :G 0 (V*), il n’y a aucune restriction sur les productions :    . On a pas


d'algorithme d'analyse efficace correspondant .
● Le type 1 :G 1 (V*), dite dépendante du contexte; toutes les productions ont la forme:
 X    ,  ,∈V * , X ∈V N , ∈V + et ∣ X ∣ ∣∣ ,(c’est­à­dire que
longueur() = longueur ()). En d’autres termes,  , représentent le ‘contexte’. Le
symbole non terminal X peut être remplacé par  si on a le contexte gauche  et le
contexte droit  . Toute grammaire dépendante du contexte possède un algorithme
d’analyse syntaxique.
● Le type 2 :G 2 (V*), dite indépendante du contexte; toutes les productions ont la forme
X   , X ∈V N , ∈V * , c’est­à­dire que le symbole non terminal X peut être
remplacé par  indépendamment du contexte dans lequel il se trouve. La grande majorité
des langages de programmation sont décrits par une grammaire indépendante du contexte.
Les grammaires indépendantes du contexte ne sont pas un strict sous­ensemble des
grammaires dépendantes du contexte (qui excluent la chaîne vide)
● Le type 3 : G 3 (V*)=R(V*), dite régulière; une telle grammaire régulière peut prendre deux
formes:
– Forme appelée grammaire linéaire à droite X  t Y où t∈V T et X ,Y ∈V N .
– Forme appelée grammaire linéaire à gauche X Y t où t∈V T et X ,Y ∈V N .
Les grammaires régulières sont un sous­ensemble des grammaires indépendantes du
contexte. Les expressions régulières désignent la forme des règles des grammaires
régulières. Toute grammaire régulière engendre un langage régulier:
En effet, à chaque régle de la forme X Y t on associe une transition Y t  X c'est à
dire « je suis dans l'état Y et j'ai le symbole t alors je passe à l'état X ».

Type Grammaire Algorithme Langage


Type 0   Machine de Turing universel
Type 1  X    avec Machine de Turing Avec contexte
∣ X ∣ ∣∣
Type 2 X Automates à pile Hors contexte
Type 3 X  t Y ou X Y t Automates d'états Réguliers

3. Gramaires hors­contexte (free­context)


Au­delà des langages réguliers, les langages hors­contexte (angl. Context­Free Languages, CFL)
ont de nombreuses applications dans l’étude des langages naturels, en compilation (syntaxe de
langages de programmation), analyse de programmes, etc.

D éfinition. Une grammaire est hors­contexte (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 .

3.1. Dérivation, Forme syntaxique et langage

D éfinition. G=<VN, VT, P, S> une grammaire hors­contexte (CGF) avec X ∈V N et


 , ∈V
*
v ∈V T Une dérivation est l’application d’une règle X →v de P au mot u=
X ∈ V∗ qui produit le mot v (on note X  ⇒ v). On écrit u ⇒* v si l’on peut dériver
le mot v du mot u, c­à­d. si on a soit u = v, ou s’il existent u1 , . . . , un ∈ V∗ tels que u ⇒ u1 ⇒ ∙ ∙ ∙ ⇒
un ⇒ 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 hors­contexte (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 hors­contexte (CGF) Une phrase  est une
forme syntaxique particulière où ∈ VT∗ : S ⇒* 

La partie droite de la dérivation (6) est une phrase.

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 hors­contexte (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 hors­contexte (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

• Une CFG qui engendre des expressions arithmétiques utilisant +, ∗ et les


variables a, b, c (langage non­régulier !) :

E →E+E| E*E | (E)| a | b| c

L'arbre syntaxique de la phrase écrite dans ce langage a + b*c

E + E

a b * c

3.2. Ambiguité

D éfinition. G=<VN, VT, P, S> une grammaire hors­contexte (CGF) est ambiguë si elle existe
une phrase w dans le langage engendré par G qui admet au moins deux arbres syntaxiques
distincts.

Exemple: la phrase a+ b*c dans le langage des expressions arithmétiques de la paragraphe


précedante admet plusieuurs arbres syntaxiques car les opérateurs + et * dans la régle ont la même
priorité. En effet, selon l'alternative de la régle et la dérivation choisies (gauche ou droite), on
obtient plusieurs arbres dont voici deux:
G: S →E
E →E+E| E*E | (E)| a | b| c
S S
E E

E E E E
+ *
a b * c a b c
+
(i) (ii)
En terme de dérivations, on a:

Forme syntaxique Régle appliquée Forme syntaxique Régle appliquée


E S→ E E S→ E
E +E E →E +E E*E E →E * E
a +E E →a E+ E*E E → E + E
a +E*E E→ E * E a+ E*E E→ a
a + b* E E→ b a+ b*E E→ b
a +b*c E→ c a + b *c E→ c
* est prioritaire que + + est prioritaire que *

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 ci­dessus. La grammaire G' est donc
non ambiguë.

Forme syntaxique Régle appliquée S


E S→ E
E +F E →E +F E
F +F E →F
P +F F→ P E + F
a +F P→ a
a + F* E F→ F * P F * P
F
a +P*E F→ P
a + b* E P→ b
P P c
a + b* F E→ F
a + b* P F→ P
a b
a + b* c P→ c
* est prioritaire que +

3.3. Classes de grammaires hors contextes


Il existe deux grandes classes de grammaires:
● Grammaires dite LR(k): Lire k symboles à partir de gauche (Left) et réduire la partie droite
de la régle de production (Reduce) par la partie gauche.
● Grammaires dite LL(k): Lire k symboles à partir de gauche (Left) et replacer la partie
Gauche de la régle de production (Left) par la partie droite.
Dans la pratique,on utilise les sous­classes LR(1) et LL(1) : lecture d'un seul symbole à la fois.
On montre que la classe des grammaires LL(k) est inclus dans la classe LR(k):
Classe LL k ⊂Classe LR k 
Dans la suite de cours, on va utiliser seulement la sous classe LL(1).

3.4. Grammaires LL(1)


Pour montrer qu'une grammaire G est LL(i), on aura besoin des ensembles suivants:

● 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):

Suiv()={ t∈V T / ∀ X   A  avec t∈ Prem , ∈V , ∈V } U Suiv  X  ^


* * +
*

T héorème. G=<VN, VT, P, S> une grammaire hors­contexte (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 hors­contexte (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→ A1 | 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→ A1 | 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''.

3.5. Analyse Syntaxique


L'analyse syntaxique est le processus qui permet de vérifier si une phrase w écrite dans un langage
engendré par une gramlmaire G respecte les régles de ce dernier ou non.
Elles existent deux grandes classes d'analyseurs syntaxiques:
● Analyseurs syntaxiques Ascendnantes qui utilisent les grammaires LR(k):
On identifie les symboles constituants la phrase à partir des feuilles de l'arbre syntaxique et
on monte dand l'arbre jusqu'à la racine (Axiome ).
Exemple: soit la phrase '' x + 2 * y '' écrite dans le langage engendré par la grammaire
suivant: P={ER → E, E → F | E '+' F | E '­' F, F → P | P '*' F | P '/' F, P → cstr | idf | '(' E ')' }

Forme syntaxique Opération


ER
x+2*y Lire x (idf)
idf + 2 * y Réduire par P → idf
P+2*y Réduire par F → P E
F+2*y Réduire par E → F
E+2*y Lire '+' E F
E + cstr * y Lire 2 (cstr)
E+P*y Réduire par P → cstr F P F
E+P*y Lire '*'
E + P * idf Lire y (idf)
E+P*P Réduire par P → idf P P
E+P*F Réduire par F → P
E+F Réduire pat F → P*F (idf) + (cstr) * (idf)
x 2 y
E Réduire pat E → E + F
ER Réduire pat ER → E
On voit bien qu' à partir de x+2*y on arrive à l'axiome ER après plusieurs lectures et réductions par
des régles de P. On dit que la phrase est syntaxiquement juste.
L'algorithme d'un analyseur syntaxique ascendant utilise l'automate fini à pile.

● Analyseurs syntaxiques Déscendnantes qui utilisent les grammaires LL(k):


On descend de la racine de l'arbre syntaxique (Axiome) jusqu'à les feuilles qui constituent la
phrase.
Exemple: soit la phrase '' x + 2 * y '' écrite dans le langage engendré par la grammaire
suivant:
P ={ER→E, E→F SF, SF→^ |'+' F SF |'­' F SF, F → P SP, SP → ^ | '*' P SP | '/' P SP, P→cstr | idf | '(' E ')' }

Forme syntaxique Opération ER

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  :

Symbole Action Exemple


X ∈V N à gauche de X   Entête de l'action : Action X() P→idf : action P()
A∈V N à droite de X   A Appel de l'action: A() P→ '(' E ')' : action P() { ...; E() ; ... }
t∈V T à droite de X  t  Test: traiter(); P→ '(' E ')'
si us='t' alors si us='(' alors lire(us); E()
lire(us);traiter() si us=')' alors lire(us)
sinon erreur() fsi sinon Erreur(' ) attendue') fsi
sinon Erreur(' ( attendue') fsi
X→ 1 |  |  | n , Choix: selon us faire P→cstr | idf | '(' E ')'
 !=^ pour i=1..n Prem(1 ): Traiter(1 ); action P()
Prem(2 ): Traiter(2 ); { selon us faire
: idf : lire(us);
Prem(n ): Traiter(n ); cstr :lire(us);
défaut: Erreur() '(' : lire(us); E();
fselon si us=')' alors lire(us)
sinon erreur(' ) attendue') fsi
autre: erreur()
fselon }
X→ 1 |  |  | n , si us!=Suiv(X) alors SP → ^ | '*' P SP | '/' P SP, P
 si ∃ j /  j= ^ selon us faire action SP()
 !=^ pour i=1..j­1, j+1..n Prem(1 ) : Traiter(1 ); { si us!=')' et us!='+' et us!='­' alors
: selon us faire
Prem(j­1 ) : Traiter(j­1 ); '*': lire(us); P(); SP();
Prem(j+1 ) : Traiter(j+1 ); '/' :lire(us); P(); SP();
: autre : erreur(' * ou / attendue')
Prem(n ) : Traiter(n ); fselon
défaut : Erreur() fsi
fselon }
fsi

Remarque:
● l'action Traiter(i ) est l'une ou la conbinaison de plusieurs actions de tableau ci­dessus. 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

Lecture Action Valeur de us


x+2*3$ lire(us);ER() us=x (idf)
: E() :
: F();SF() :
: P() ;SP();SF() :
x+2*3$ us=idf donc lire(us) sortir de P() us='+'
: SP();SF() :
: us='+' donc sortir de SP() :
: SF() :
x+2*3$ us!=')' et us!='$' et us='+' donc lire(us); F();SF() us=2 (cstr)
: F();SF() :
: P();SP();SF() :
x+2*3$ us=cstr donc lire(us); sortir de P() us='*'
: SP();SF() :
x+2*3$ us!='+' et us='*' donc lire(us);P(); SP() us=3 (cstr)
: P();SP();SF() :
x+2*3$ us=cstr donc lire(us);sortir de P() us='$'
SP();SF() :
us='$' donc sortir de SP() :
SF() :
us='$' donc sortir de SF();sortir de E() :
us='$' pas d'erreur alors sortir de ER() :
On sort de AnalyseurSyntaxique sans erreur

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

Lecture Action Valeur de us


*3$ lire(us);ER() us='*'
: E() :
: F();SF() :
: P() ;SP();SF() :
*3$ us!=idf us!=cstr et us!='(' donc autre: us='*'
erreur('' idf ou cstr ou '(' attendu'' )
On sort de l'Analyseur avec une erreur syntaxique

Vous aimerez peut-être aussi