,
, l'axiome est
, les
règles sont données par:
Pour un mot de
, il est immédiat de déterminer
tel que
En effet, si est de longueur
, ou bien
et le
résultat de l'analyse syntaxique se limite à
, ou bien
n'appartient pas au langage engendré par la grammaire.
Si est de longueur supérieure à
, il suffit de connaître les
deux premières lettres de
pour pouvoir retrouver
. Si ces
deux premières lettres sont
, c'est la règle
qui a été appliquée, si ces deux lettres sont
alors c'est
la règle
. Tout autre début de règle conduit à un
message d'erreur.
Ce qui vient d'être dit pour retrouver en utilisant les deux
premières lettres de
se généralise sans difficulté à la
détermination du
mot
de
la dérivation à partir de
. On décompose d'abord
et
en:
et on procède en fonction des deux premières lettres de .
Cet algorithme reprend les grandes lignes de la descente récursive
avec une différence importante: la boucle while
qui consistait
à appliquer chacune des règles de la grammaire est remplacée par un
examen de certaines lettres du mot à analyser, examen qui permet de
conclure sans retour arrière. On passe ainsi d'une complexité
exponentielle à un algorithme en . En effet, une manière
efficace de procéder consiste à utiliser une pile pour gérer le mot
qui vient de la décomposition
. La
consultation de la valeur en tête de la pile et sa comparaison avec
la lettre courante de
permet de décider de la règle à
appliquer. L'application d'une règle consiste alors à supprimer la
tête de la pile (membre gauche de la règle) et à y ajouter le mot
formant le membre droit en commençant par la dernière lettre.
Nous avons appliqué cette technique pour construire l'arbre de
syntaxe abstraite associé à une expression préfixée. Dans ce qui
suit, le mot à analyser est une variable globale de même que la
variable entière pos qui indique la position à laquelle on se
trouve dans ce mot.
function ArbSyntPref: Arbre; var a, b, c: Arbre; x: char; begin if f[pos] = 'a' then begin a := NouvelArbre('a', nil, nil); pos := pos + 1; end else if (f[pos] = '(') and (f[pos+1] in {'+', '*'}) then begin x := f[pos + 1]; pos := pos + 2; b := ArbSyntPref; c := ArbSyntPref; a := NouvelArbre(x, b, c); if f[pos] = ')' then pos := pos + 1 else Erreur(pos); end else Erreur(pos); ArbSyntPref := a end;
L'algorithme d'analyse syntaxique donné ici peut s'étendre
à toute grammaire dans laquelle pour chaque couple de règles et
, les mots qui dérivent de
et
n'ont pas des
facteurs gauches égaux de longueur arbitraire. Ou de manière plus
précise, il existe un entier
tel que tout facteur gauche de
longueur
appartenant à
d'un mot qui dérive de
est
différent de celui de tout mot qui dérive de
. On dit alors que
la grammaire est
et on peut alors démontrer:
En fait, cet algorithme est surtout utile pour . Nous donnons ici
ses grandes lignes sous forme d'un programme Pascal qui utilise une
fonction
Predicteur
calculée au préalable. Pour un
élément
de
et un mot
de longueur
, cette fonction
indique le numéro de l'unique règle
telle que
se
dérive en un mot commençant par
ou qui indique
Omega
si
aucune telle règle n'existe. Dans l'algorithme qui suit, on utilise
une pile comme variable globale. Elle contient la partie du mot
qui doit engendrer ce qui reste à lire dans
. Nous en donnons ici
une forme abrégée.
function Analyse(f: Mot; pos: integer): boolean; var i: integer; begin pos := 1; while Pvaleur(p) = f[pos] do begin Psupprimer(p); pos := pos + 1; end; if Pvide(p) and f[pos] = '$' then Analyse := true else begin y := Pvaleur(p); if not Auxiliaire(y) then Analyse := false else begin i := Predicteur (y, pos, pos+k-1); if i <> Omega then begin writeln (y, '->', regle[y,i]); Pinserer(regle[y,i], p); Analyse := Analyse (f, pos); end else Analyse := false; end;