On souhaite créer un programme qui reconnaît le langage suivant : « Les expressions correctes sont constituées d'un nombre quelconque, mais non nul, de 0, suivi d'un nombre quelconque, mais non nul, de 1. »
On suivra cette démarche :
Voici la grammaire du langage à reconnaître :
<expression> ::= <groupe0> <groupe1>
<groupe0> ::= «0» <suite0>
<suite0> ::= <groupe0>
::=
<groupe1> ::= «1» <suite1>
<suite1> ::= <groupe1>
::=
Pour la rédiger, on a suivi les règles suivantes :
Voici le code de l'analyseur pur : il répond par « bon » ou « mauvais », c'est-à-dire 1 ou 0.
#include <stdio.h>
char s[512];
char *ss;
int expression(){
if (groupe0()==1)
return groupe1();
return 0;
}
int groupe0(){
if (*ss == '0'){
ss++;
return suite0();
}
return 0;
}
int suite0(){
if (groupe0() == 0)
return 1;
return 1;
}
Il faut constater le lien très fort entre ce code et la grammaire ci-dessus. On n'a à réfléchir qu'au moment de la rédaction de la grammaire, le code est alors une conséquence directe de cette dernière. A un point tel qu'on verra qu'il est possible de générer automatiquement le code à partir de la grammaire, à l'aide d'outils prévus à cet effet.
Notons qu'une fonction prévue pour analyser une sous-expression ne connaît pas ce qui précède, et ne s'occupe pas de ce qui suit.
Passons au programme principal :
int main(){
printf("Une expression à analyser ? \n");
scanf("%s",s);
ss = s;
if (expression()==1)
if (*ss == '\0')
printf("Bon \n");
else
printf("Mauvais\n");
else
printf("Mauvais\n");
}
Remarque : Toujours commencer par l'analyseur syntaxique pur.
On souhaite dorénavant que les retours de notre analyseur soient plus parlant. On va donc renvoyer du texte, des messages d'erreurs...
int groupe0(){
if (*ss == '0'){
ss++;
return suite0();
}
printf("L'expression doit commencer par 0\n");
return 0;
}
int suite0(){
if (*ss == '0'){
ss++;
return suite0();
}
return 1;
}
Le programme principal devient alors :
int main(){
printf("Une expression à analyser ? \n");
scanf("%s",s);
ss = s;
if (expression()==1)
if (*ss == '\0')
printf("Bon \n");
else if (*ss == '0')
printf("Pas de 0 apres le(s) un(s).\n");
else
printf("Caractère interdit : %c\n",*ss);
}
int groupe0(){
if (*ss == '0'){
ss++;
return 1+suite0();
}
printf("L'expression doit commencer par 0\n")
return 0;
}
int suite0(){
if (*ss == '0'){
ss++;
return 1+suite0();
}
return 0;
}
Le programme principal devient alors :
int main(){
printf("Une expression a analyser ? \n");
scanf("%s»,s);
ss = s;
Expression = expression()
if (*ss == '\0')
printf("Bon \n");
else if (*ss == '0')
printf("Nombre de 0 : d",expression.zero, expression.un);
else
printf("Caractère interdit : %c\n",*ss);
}
où la structure Expression et la fonction expression() sont ainsi définis :
struct Expression{
int zero;
int un;
}
struct Expression expression(){
struct Expression a;
a.zero = groupe0();
if (a.zero !=0)
a.un = groupe1();
return a;
}
Cet exemple, et d'autres, seront (re)vus en TP.