M1

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 !