Fichier Lex
%{
#include "y.tab.h"
#include <string.h>
typedef struct element {
char *mot;
int token;
struct element *suivant;
} Liste;
int mode = 0;
Liste *tete = NULL;
int rechercher(Liste *liste, char *mot);
Liste *inserer(Liste *liste, char *mot, int token);
Liste *creerMaillon(char *mot, int token);
/**
* La règle ligne 45 permet de traiter tous les cas où un mot est entré
* au clavier.
*
* Lorsque l'on rencontre un mot-clé (e.g. "pronom" ou "verbe"), on
* sait que l'on doit passer en mode apprentissage ; on change donc
* la valeur de `mode` pour refléter le type de tokens que l'on souhaite
* faire apprendre à l'analyseur.
*
* Le mode est remis à 0 à chaque fois qu'une nouvelle ligne est créée, c'est
* à dire à chaque fois qu'un élément `\n` est présent (c.f. ligne 64).
*
* -----------------------------------------------------------------------
*
* Dans le cas où le mode est à 0 (c'est à dire que l'on n'a pas rencontré de
* mot-clé en début de ligne), on fait appel à Yacc pour traiter les mots que
* l'on rencontre en utilisant la fonction `rechercher` qui va renvoyer un token.
*
* Le token sera ensuite traité par Yacc qui essaiera de construire une pile de
* tokens pour l'associer à une règle et réaliser l'action en conséquence.
*
* Les tokens définies dans le fichier Yacc sont présents ici grâce au include
* ligne 2.
*/
%}
%%
[a-zA-Z]+ {
if (strcmp(yytext, "nom") == 0)
mode = 1;
else if (strcmp(yytext, "pronom") == 0)
mode = 2;
else if (strcmp(yytext, "verbe") == 0)
mode = 3;
else if (strcmp(yytext, "adjectif") == 0)
mode = 4;
else if (strcmp(yytext, "adverbe") == 0)
mode = 5;
else {
if (mode > 0)
tete = inserer(tete, yytext, mode);
else
return rechercher(tete, yytext);
}
}
" "+ ;
\n { mode = 0; }
%%
/**
* Permet de créer un nouvel élément de la liste chaînée.
*
* Paramètres :
*
* mot - Chaîne de caractères représentant le mot.
* token - Numéro de token / unité syntaxique à associer.
*/
Liste *creerMaillon(char *mot, int token) {
int i;
Liste *element = (Liste *)malloc(sizeof(Liste));
element->mot = (char *)malloc(sizeof(char) * strlen(mot));
element->token = token;
element->suivant = NULL;
for (i = 0; mot[i] != '\0'; i++)
element->mot[i] = mot[i];
element->mot[i] = '\0';
return element;
}
/**
* Permet d'insérer un nouvel élément en tête d'une liste
* chaînée.
*
* La nouvelle tête de la liste est renvoyée.
*
* Paramètres :
*
* liste - L'ancienne tête de la liste.
* mot - La chaîne contenant le mot.
* token - Le numéro de token / unité syntaxique à associer.
*/
Liste *inserer(Liste *liste, char *mot, int token) {
Liste *nouveau = creerMaillon(mot, token);
nouveau->suivant = liste;
return nouveau;
}
/**
* Permet de rechercher un élément dans une liste chaînée et
* de renvoyer son numéro de token / unité syntaxique.
*
* Correspondances entre modes et tokens Yacc :
*
* 1 - Nom | Sujet
* 2 - Pronom _|
* 3 - Verbe
* 4 - Adjectif | Complément
* 5 - Adverbe _|
*
* Paramètres :
*
* liste - La liste chaînée à parcourir.
* mot - La représentation en chaîne de caractères du mot.
*/
int rechercher(Liste *liste, char *mot) {
if (!liste) {
printf("La liste des tokens connus est vide !\n");
return -1;
}
Liste *courant = liste;
while (courant) {
if (strcmp(courant->mot, mot) == 0) {
switch(courant->token) {
case 1:
return NOM;
case 2:
return PRONOM;
case 3:
return VERBE;
case 4:
return ADJECTIF;
case 5:
return ADVERBE;
}
}
courant = courant->suivant;
}
return -1;
}
Fichier Yacc
%{
#include <stdio.h>
#include <stdlib.h>
int yyparse();
int yylex();
int yyerror(char *s);
%}
%token NOM PRONOM VERBE ADJECTIF ADVERBE
%%
phrase : sujet verbe complement
{ printf("La pharase est reconnue bro !\n"); }
;
sujet : NOM
| PRONOM
;
verbe : VERBE
;
complement : ADJECTIF
| ADVERBE
;
%%
#include "lex.yy.c"
Fichier Makefile
all: compile
compile: exo2.l exo2.y
yacc -d exo2.y
lex exo2.l
gcc -o exo2 y.tab.c -ly -ll -Wall -Wextra -O2
Exemple d'exécution
$ make
$ ./exo2
pronom je
verbe suis
adjectif libertine
je suis libertine
La pharase est reconnue bro !