informatique (MP2I/MPI) · Chapitre 30 · Exercice de TD
Ce que protège le dernier contrôle de l'analyseur
Grammaires non contextuelles · niveau 2
Énoncé
L'analyseur du chapitre se termine par
s ();
if !pos <> n then raise Echec (* tout le mot doit être consommé *)
Que se passe-t-il si l'on retire cette ligne ? Donner deux mots qui seraient alors acceptés à tort.
Corrigé
Sans cette ligne, l'analyseur accepte tout mot dont un préfixe appartient au langage, et ignore ce qui suit.
Deux témoins, obtenus en exécutant les deux versions :
| Mot | avec le contrôle | sans le contrôle |
|---|---|---|
c | accepté | accepté |
acbc | accepté | accepté |
cc | refusé | accepté à tort |
cab | refusé | accepté à tort |
acb | refusé | refusé |
aa | refusé | refusé |
Sur cc, la fonction s lit le premier c par la règle , rend la main, et il reste un caractère que personne ne regarde. Sur cab, il en reste deux.
Pourquoi acb reste refusé : là, l'échec vient de l'intérieur — après a, la fonction t appelle s, qui exige un c et trouve un b. Le contrôle final n'attrape que les échecs par excès, pas ceux par défaut.
La leçon de spécification. Un analyseur par descente récursive répond en vérité à la question « un préfixe du mot est-il dans le langage ? ». La question demandée est « le mot est-il dans le langage ? ». Les deux ne se rejoignent qu'à la dernière ligne : on a écrit du code qui répond à une question voisine de celle qu'on posait.
Et l'on ne s'en aperçoit qu'aux frontières — le mot vide, le mot réduit à un préfixe valide, le mot valide suivi d'un caractère. C'est la règle du chapitre chap:discipline : aucun cas « du milieu » ne révèle cette faute-là.