<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">

<article lang="fr">
  <articleinfo>
    <title>Guide pratique et introduction à Lex et Yacc</title>

    <subtitle>
    
      Adaptation française du guide pratique <foreignphrase 
      lang="en">Lex and YACC primer/HOWTO</foreignphrase>
    
    </subtitle>

    <releaseinfo>Version&nbsp;: 0.8.fr.1.0</releaseinfo>

    <pubdate>2 mai 2008</pubdate>

    <author>
      <firstname>Bert</firstname>

      <surname>Hubert</surname>

      <affiliation>
        <orgname>PowerDNS BV</orgname>

        <address>
          <email>bert CHEZ powerdns POINT com</email>
         </address>
      </affiliation>

    </author>

  <othercredit role="traduction" class="translator">
     <firstname>Silvio</firstname>
     <surname>Morandi</surname>
     <contrib>Adaptation française</contrib>
     <email>s POINT morandi CHEZ gmail POINT com</email>
  </othercredit>

<!-- À remplir par le relecteur

  <othercredit role="relecture" class="translator">
    <firstname>Alain</firstname>
    <surname>Boulé</surname>
    <contrib>Relecture de la version française</contrib>
    <email>alain POINT boule CHEZ free POINT fr</email>
  </othercredit>

-->

  <othercredit role="publication" class="copyeditor">
    <firstname>Jean-Philippe</firstname>
    <surname>Guérard</surname>
    <contrib>Préparation de la publication de la v.f.</contrib>
    <email>fevrier CHEZ tigreraye POINT org</email>
  </othercredit>


  <!-- Historique des révisions -->

  <revhistory>

    <revision>
      <revnumber>0.8.fr.1.0</revnumber>
      <date>2008-05-02</date>
      <authorinitials>SM, JPG</authorinitials>
      <revremark>Première traduction française.</revremark>
    </revision>

    <revision>
      <revnumber>0.8</revnumber>
      <date>2004-09-20</date>
      <authorinitials>BH</authorinitials>
      <revremark>

        Version originale.
    
      </revremark>
    </revision>
    
  </revhistory>

    <abstract>
      <para>
      
      Ce document tente de vous aider à commencer à utiliser Lex et 
      YACC.
      
      </para>
    </abstract>
  </articleinfo>

  <section>
    <title>Introduction</title>

    <para>Bienvenue, cher lecteur.</para>

    <para>
    
    Quelle que soit la durée durant laquelle vous avez programmé sous un 
    environnement Unix, vous avez rencontré les programmes <emphasis 
    role="bold">mystiques</emphasis> Lex et YACC, ou tels qu'ils sont 
    connus des utilisateurs de GNU/Linux à travers le monde, Flex et 
    Bison; où Flex est une implémentation de Lex par Vern Paxson et 
    Bison la version GNU de YACC. Nous allons appeler ces programmes Lex 
    et YACC dans ce document - les nouvelles versions sont compatibles 
    "vers le haut", vous pouvez donc utiliser Flex et Bison pour essayer 
    nos exemples.
    
    </para>

    <para>
    
    Ces programmes sont très utiles, mais comme pour votre compilateur 
    C, leur page de manuel n'explique pas le langage qu'ils comprennent, 
    ni comment les utiliser. YACC utilisé en combinaison avec Lex est 
    vraiment surprenant, cependant, la page de manuel ne décrit pas comment 
    intégrer du code généré par Lex dans votre programme en Bison.
    
    </para>

    <section>
      <title>Ce que ce document n'est PAS</title>

      <para>Il existe de nombreux livres qui traitent de Lex et YACC. Lisez
      ces ouvrages de toute manière si vous souhaitez en savoir plus. Ils
      apportent beaucoup plus d'information que ce nous sommes en mesure de
      voir ici. Vous pouvez consulter la section <quote>lectures pour approfondir</quote>
      à la fin. Ce document a pour but de vous aider à vous en sortir lors de
      la création de vos premiers programmes avec Lex &amp; YACC.</para>

      <para>La documentation fournie avec Lex &amp; YACC est elle aussi
      excellente, mais peu pédagogique. Elle est cependant complémentaires
      avec ce guide pratique, et est aussi référencée à la fin.</para>

      <para>Je ne suis absolument pas un expert de Lex &amp; Yacc. lorsque
      j'ai commencé à écrire ce document, j'avais exactement deux jours de
      pratique. Tout ce que j'ai cherché à faire, c'est rendre ces deux jours
      les plus simple possibles pour vous.</para>

      <para>
      
      N'attendez pas de ce guide pratique qu'il vous montre comment 
      coder proprement en Lex et YACC. Les exemples ont été laissé 
      volontairement très simples et il y a sûrement de meilleures 
      manières de les écrire. Si vous savez comment, s'il vous plaît, 
      contactez moi.
      
      </para>
    </section>

    <section>
      <title>Téléchargement</title>

      <para>Notez que vous pouvez télécharger tous les exemples montrés sous
      forme de code source. Visitez la Homepage pour plus de détails.</para>
    </section>

    <section>
      <title>Licence</title>

      <para>Copyright (c) 2001 by bert hubert. This material may be
      distributed only subject to the terms and conditions set forth in the
      Open Publication License, vX.Y or later (the latest version is presently
      available at http://www.opencontent.org/openpub/).</para>

      <para>Traduction à titre informative et sans valeur juridique :</para>

      <para>Copyright (c) 2001, bert hubert. Ce programme ne peut être
      distribué que selon les conditions générales établies dans l'<quote>Open
      Publication License</quote>, vX.Y ou ultérieure (la dernière version est
      disponible à http://www.opencontent.org/openpub/).</para>
    </section>
  </section>

  <section>
    <title>Ce que Lex &amp; YACC peuvent faire pour vous</title>

    <para>Utilisés proprement, ces langages vous permettent d'analyser
    facilement des langages complexes. C'est un sacré coup de pouce lorsque
    vous souhaitez lire un fichier de configuration, ou que vous souhaitez
    écrire un compilateur pour un langage que vous (ou n'importe qui d'autre)
    avez inventé.</para>

    <para>Avec un peu d'aide, ce que j'espère que ce document vous apportera,
    vous découvrirez finalement que vous n'écrirez plus jamais d'analyseur
    syntaxique à la main: Lex &amp; YACC sont les outils pour le faire.</para>

    <section>
      <title>Ce que fait chaque programme</title>

      <para>Même si ces programmes fonctionnent de manière optimale ensemble,
      ils servent chacun à un but différent. Les prochains chapitres
      expliqueront exactement l'action de chacun d'entre eux.</para>
    </section>
  </section>

  <section>
    <title>Lex</title>

    <para>Ce programme génère ce que l'ont appelle un analyseur lexical. Il
    s'agit d'une fonction qui prend comme argument un flux de caractères, et
    dès qu'il aperçoit un groupe qui correspond à un mot clef, effectue une
    certaine action. Un exemple très simple :</para>

    <programlisting>
%{
#include &lt;stdio.h&gt;
%}

%%
stop    printf("Stop command received\n");
start   printf("Start command received\n");
%%
</programlisting>

    <para>La première partie, entre les paires %{ et %}, est inclue
    directement dans la sortie. Nous avons besoin de cela, car nous
    utiliserons printf, qui est définit dans stdio.h, plus tard.</para>

    <para>Les parties sont séparées par %%, donc la première ligne de la
    seconde section commence par le mot-clef <quote>stop</quote>. A chaque fois que le
    mot-clef <quote>stop</quote> est rencontré dans l'entrée, le reste de la ligne ( ici
    un appel à printf() ) est exécuté.</para>

    <para>En plus de <quote>stop</quote> nous avons aussi définit <quote>start</quote>, qui par
    ailleurs effectue sensiblement la même chose.</para>

    <para>Nous terminons la seconde partie avec %% encore.</para>

    <para>Pour compiler l'exemple 1, faire ceci:</para>

    <screen>
lex example1.l
cc lex.yy.c -o example1 -ll
</screen>

    <note>
      <para>si vous utilisez Flex, au lieu de Lex, vous pouvez avoir à changer
      -|| en -lfl ans le script de compilation. RedHat 6.x et SuSE en ont
      besoin aussi, même en utilisant Flex au lieu de Lex !</para>
    </note>

    <para>Ceci générera un fichier <quote>exemple1</quote>. Si vous le lancez, il
    attendra que de vous tapiez une entrée. Même si vous tapez une entrée qui
    n'est pas <quote>matchée</quote> par un mot-clef (ici stop et start) it's output
    again. Si vous entrez 'stop', il affichera la sortie suivante <quote>stop
    command received</quote>;</para>

    <para>Terminate with a EOF (^D).</para>

    <para>Vous pouvez vous demander comment fonctionnent ces programmes, car
    nous n'avons pas définit de fonction main(). Cette fonction est définit
    pour vous dans libl (liblex) que nous avons compilé avec le programme
    grâce à la commande -ll.</para>

    <section>
      <title>Analyser les expressions régulières</title>

      <para>Cet exemple n'était pas très utile en soit, et notre suivant ne
      sera pas mieux. Il va cependant nous montrer comment utiliser les
      expressions régulières en Lex, qui seront très utiles plus tard.</para>

      <para>Example 2:</para>

      <programlisting>
%{
#include &lt;stdio.h&gt;
%}

%%
[0123456789]+           printf("NUMBER\n");
[a-zA-Z][a-zA-Z0-9]*    printf("WORD\n");
%%
</programlisting>

      <para>Ce fichier Lex explique deux types de mots clés (symboles): WORD
      et NUMBER. Les expressions régulières peuvent être un peu intimidantes,
      mais avec un peu de travail, elles sont très simples à comprendre.
      Examinons le mot clé NUMBER:</para>

      <para>[0123456789]+</para>

      <para>Cela signifie: une séquence de un ou plus de caractères du groupe
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }. On aurait aussi pu faire plus court
      :</para>

      <para>[0-9]+</para>

      <para>Maintenant, le mot clé WORD est un peu plus complexe:</para>

      <para>[a-zA-Z][a-zA-Z0-9]*</para>

      <para>a première partie ne repère qu'un et un seul caractère entre 'a'
      et 'z', ou entre 'A' et 'Z'.En d'autres termes, une lettre. Cette lettre
      initiale doit ensuite être suivie par zéro ou plus de caractères qui
      sont soit une lettre, soit un chiffre. Pourquoi avoir utilisé un
      astérisque ici ? Le '+' signifie 1 ou plus de repérages, mais un mot
      peut très bien n'être qu'un seul caractère, que nous avons alors déjà
      matché. La seconde partie peut donc n'avoir rien à matcher, nous
      écrivons donc un '*'.</para>

      <para>De cette manière , nous avons singé le comportement de nombreux
      langages de programmation qui requièrent qu'un nom de variable <quote>doive</quote>
      commencer par une lettre, mais puisse contenir des chiffres ensuite. En
      d'autres mots 'temperature1' est un nom valide, mais '1temperature ' ne
      l'est pas.</para>

      <para>Essayez de compiler Example2, tout comme Exemple1, et nourrissez
      le d'un peu de texte. Voici une <emphasis role="bold">session</emphasis>
      d'échantillons:</para>

      <screen>
$ ./example2
foo
WORD

bar
WORD

123
NUMBER

bar123
WORD

123bar
NUMBER
WORD
</screen>

      <para>Vous pourriez aussi vous demander pourquoi il y a un retour à la
      ligne dans la sortie. La raison est simple : il était dans l'entrée, n'a
      été matché nul part, il apparaît donc dans la sortie.</para>

      <para>La page de man de Flex documente les expressions régulières en
      détail. Beaucoup de gens trouvent que cellle des expressions régulières
      de perl est aussi très utile, même si Flex n'implémente pas tout ce que
      perl fait.</para>

      <para>Vérifiez que vous n'avez pas crée de match de taille nulle comme
      '[0-9]*', votre lexer pourrait être perdu et pourrait commencer à
      matcher des chaînes vides en boucle</para>
    </section>

    <section>
      <title>Un exemple plus compliqué pour une syntaxe proche du C</title>

      <para>Imaginons que nous voulions analyser un fichier qui ressemble à
      ceci:</para>

      <programlisting>
logging {
        category lame-servers { null; };
        category cname { null; };
};

zone "." {
        type hint;
        file "/etc/bind/db.root";
};
</programlisting>

      <para>On voit clairement un certain nombre de catégories (symboles) dans
      ce fichier:</para>

      <itemizedlist>
        <listitem>
          <para>WORD, (mot) comme 'zone' et 'type'</para>
        </listitem>

        <listitem>
          <para>FILENAME, (nom de fichier) comme '/etc/bind/db.root'</para>
        </listitem>

        <listitem>
          <para>QUOTE, (guillemets)comme celles entourant le nom du
          fichier</para>
        </listitem>

        <listitem>
          <para>OOBRACE, (crochet ouvrant) {</para>
        </listitem>

        <listitem>
          <para>EBRACE, (crochet fermant) }</para>
        </listitem>

        <listitem>
          <para>SEMICOLON, (point virgule) ;</para>
        </listitem>
      </itemizedlist>

      <para>Le fichier correspondant en Lex est Exemple 3:</para>

      <programlisting>
%{
#include &lt;stdio.h&gt;
%}

%%
[a-zA-Z][a-zA-Z0-9]*    printf("WORD ");
[a-zA-Z0-9\/.-]+        printf("FILENAME ");
\"                      printf("QUOTE ");
\{                      printf("OBRACE ");
\}                      printf("EBRACE ");
;                       printf("SEMICOLON ");
\n                      printf("\n");
[ \t]+                  /* ignore whitespace */;
%%
</programlisting>

      <para>Quand nous donnons notre ficher à notre <emphasis
      role="bold">lexer</emphasis> généré par ce fichier Lex (en utilisant
      example3.compile), nous obtenons:</para>

      <screen>
WORD OBRACE 
WORD FILENAME OBRACE WORD SEMICOLON EBRACE SEMICOLON 
WORD WORD OBRACE WORD SEMICOLON EBRACE SEMICOLON 
EBRACE SEMICOLON 

WORD QUOTE FILENAME QUOTE OBRACE 
WORD WORD SEMICOLON 
WORD QUOTE FILENAME QUOTE SEMICOLON 
EBRACE SEMICOLON 
</screen>

      <para>Lorsque nous comparons ceci avec le fichier cité plus haut, il est
      clair que nous l'avons 'symbolisée'. Chaque partie du fichier de
      configuration à été analysée, et convertie en symbole.</para>

      <para>Et c'est exactement ce donc nous avons besoin pour utiliser YACC
      Correctement.</para>
    </section>

    <section>
      <title>Ce que nous avons vu</title>

      <para>Nous avons vu que Lex est capable de lire une entrée arbitraire,
      et d'analyser ce qu'est chaque partie. C'est ce qu'on appelle l'analyse
      lexicale.</para>
    </section>
  </section>

  <section>
    <title>YACC</title>

    <para>YACC peut analyser syntaxiquement un flux composé de symboles avec
    certaines valeurs. Cela décrit parfaitement la relation entre YACC et Lex.
    Yacc n'a aucune idée de ce que sont les <emphasis role="bold">'flux en
    entrée '</emphasis>, il a besoin de symboles au préalablement traités.
    Alors que vous pourriez écrire vous même votre propre analyseur lexical,
    nous allons laisser Lex s'en charger.</para>

    <para>Une note sur les grammaires et les analyseurs syntaxiques. Lorsque
    YACC à vu le jour, cet outil était utilisé pour analyser les fichier
    d'entrée des compilateurs. Les programmes écrits pour un langage de
    programmation ne sont pas ambigus (cad qu'ils n'ont qu'un seul sens). En
    tant que tel, YACC ne peut pas surmonter une ambiguïté ou un conflit
    décalage/réduction. Vous pourrez en apprendre plus sur YACC et les
    problèmes d'ambiguïté ou les conflits décalage/réduction dans le chapitre
    'Conflits '.</para>

    <section>
      <title>4.Un contrôleur simple de thermostat</title>

      <para>Imaginons que nous ayons un thermostat que nous voulons contrôler
      avec un langage simple. Un dialogue avec le thermostat pourrait
      ressembler à ceci :</para>

      <screen>
heat on
        Heater on!
heat off
        Heater off!
target temperature 22
        New temperature set!
</screen>

      <para>Les symboles que nous avons besoin de reconnaître sont : heat,
      on/off (STATE), target, température, NUMBER.</para>

      <para>L'analyseur lexical Lex (Exemple 4) est :</para>

      <programlisting>
%{
#include &lt;stdio.h&gt;
#include "y.tab.h"
%}
%%
[0-9]+                  return NUMBER;
heat                    return TOKHEAT;
on|off                  return STATE;
target                  return TOKTARGET;
temperature             return TOKTEMPERATURE;
\n                      /* ignore end of line */;
[ \t]+                  /* ignore whitespace */;
%%
</programlisting>

      <para>Nous pouvons remarquer deux changements importants. Premièrement,
      nous 'incluons' le fichier 'y.tab.h', et ensuite nous n'affichons plus
      rien, nous retournons les noms des ymboles. Ce changement est causé par
      le fait que nous fournissons désormais le tout à YACC, ce qui n'a plus
      aucun rapport avec ce que nous obtenons à l'écran. <emphasis
      role="bold">Y.tab.h has definitions for these tokens.</emphasis></para>

      <para>Mais d'où viens y.tab.h ? Il est généré par YACC à partir du
      fichier grammaire que nous sommes allons créer. Comme notre langage est
      très basique, voilà notre grammaire:</para>

      <programlisting>
commands: /* empty */
        | commands command
        ;

command:
        heat_switch
        |
        target_set
        ;

heat_switch:
        TOKHEAT STATE
        {
                printf("\tHeat turned on or off\n");
        }
        ;

target_set:
        TOKTARGET TOKTEMPERATURE NUMBER
        {
                printf("\tTemperature set\n");
        }
        ;
</programlisting>

      <para>La première partie est ce que j'appelle la 'racine'. Elle nous
      explique que nous avons des commandes, et que ces commandes consistent
      en <emphasis role="bold">individual 'command' parts</emphasis>. Comme
      vous pouvez le voir, cette règle es très récursive car elle contient
      encore le mot <quote>command</quote>. Ce qui signifie que le programme est désormais
      capable de réduire une série de commandes une par une. Lisez le chapitre
      'Comment fonctionnent Lex et YACC en détail ' pour des détails
      importants sur la récursivité.</para>

      <para>la seconde règle définit ce qu'est une commande. Nous ne
      supportons que deux types de commande, la commande 'heat_switch' et la
      commande 'target_set'. C'est ce que le symbole |- signifie: une commande
      peut être ou un 'heat-switch' ou un 'target-set'.</para>

      <para>Un heat-switch consiste en un symbole HEAT qui est simplement le
      mot 'heat' suivit d'un état (que nous définirons dans le Fichier Lex
      comme 'on' ou 'off').</para>

      <para>Plus compliqué: le 'target_set' qui consiste en un symbole TARGET
      (le mot target), le symbole TEMPERATURE (le mot temperature) et un
      nombre.</para>

      <section>
        <title>Un fichier YACC complet</title>

        <para>La section précédente n'a montrée que la partie grammaticale du
        fichier YACC, mais il y a plus. Voici l'en tête que nous avons
        omis:</para>

        <programlisting>
%{
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
 
void yyerror(const char *str)
{
        fprintf(stderr,"error: %s\n",str);
}
 
int yywrap()
{
        return 1;
} 
  
main()
{
        yyparse();
} 

%}

%token NUMBER TOKHEAT STATE TOKTARGET TOKTEMPERATURE
</programlisting>

        <para>La fonction yyerror() est appelée par YACC si il trouve une
        erreur. Nous renvoyons simplement le message reçu, mais il y a des
        choses plus intelligente à faire avec. Lisez la section <quote>lectures
        pour approfondir</quote> pour en savoir plus.</para>

        <para>La fonction yywarp() peut être utilisée pour continuer la
        lecture depuis un autre fichier. C'est appelée à EOF et vous pouvez
        ensuite ouvrir un autre fichier et renvoyer 0; ou renvoyer 1 qui
        indique qu'il s'agit de la fin. Pour en savoir plus, lisez le chapitre
        : 'Comment fonctionnent Lex et YACC en détail '.</para>

        <para>Ensuite, il y a la fonction main(), qui ne fait rien de
        particulier, mais lance le processus</para>

        <para>La dernière ligne définit simplement les symboles qui seront
        utilisés. <emphasis role="bold">Ce sont les sorties qui utilisent
        y.tab.h si YACC est appelé avec l'option -d &lt;-- ici je ne suis pas
        sur d'avoir compris le sens de la phrase en anglais.</emphasis></para>
      </section>

      <section>
        <title>Compiler et utiliser le contrôleur de thermostat</title>

        <screen>
lex example4.l
yacc -d example4.y
cc lex.yy.c y.tab.c -o example4 
</screen>

        <para>Certaines choses ont changées. Nous appelons aussi YACC pour
        compiler notre grammaire, ce qui crée y.tab.c et y.tab.h. Nous
        appelons appelons ensuite Lex comme d'habitude. Lorsque nous
        compilons, nous retirons le drapeau -ll: nous avons désormais notre
        propre fonction main() et nous n'avons pas besoin de celle fournis par
        libl.</para>

        <note>
          <para>Si vous obtenez une erreur indiquant que votre compilateur
          n'est pas capable de trouver 'yylval ', ajoutez ceci à l'éxemple4.1,
          juste sous #include &lt;y.tab.h&gt;:</para>

          <programlisting>
extern YYSTYPE yylval;
</programlisting>

          <para>Ceci est expliqué dans le chapitre 'comment Lex et YACC
          fonctionnent en détail.</para>
        </note>

        <para><emphasis role="bold">Une session d'exemple </emphasis>:</para>

        <screen>
$ ./example4 
heat on
        Heat turned on or off
heat off
        Heat turned on or off
target temperature 10
        Temperature set
target humidity 20
error: parse error
$
</screen>

        <para>Ce n'est pas vraiment ce que l'ont avait prévu d'obtenir, mais
        pour garder une courbe d'apprentissage praticable nous ne pouvons pas
        montrer toutes les possibilités en une fois.</para>
      </section>
    </section>

    <section>
      <title>Étendre le thermostat afin de supporter les paramètres</title>

      <para>Comme nous l'avons vu, nous analysons désormais syntaxiquement les
      commandes du thermostat correctement, et marquons mêmes les erreurs
      correctement. Mais comme vous pouvez l'avoir deviné d'après le titre le
      programme n'a aucune idée de ce qu'il doit faire, <emphasis
      role="bold">it does not get passed any of the values you
      enter</emphasis>.</para>

      <para>Commençons par ajouter la possibilité de lire la nouvelle
      température cible. Pour faire cela, nous avons besoin de lire le NUMBER
      <emphasis role="bold">matché</emphasis> dans l'analyseur lexical pour le
      convertir en valeur entière, qui pourra ensuite être lue avec le
      YACC.</para>

      <para>A chaques fois que le Lex <emphasis role="bold">matche</emphasis>
      une cible, il place le texte <emphasis role="bold">matché</emphasis>
      dans la suite de caractères 'yytext'. YACC, lui, espère trouver une
      valeur dans la variable 'yylval'. Dans l'exemple 5, nous voyons la
      solution triviale:</para>

      <programlisting>
%{
#include &lt;stdio.h&gt;
#include "y.tab.h"
%}
%%
[0-9]+                  yylval=atoi(yytext); return NUMBER;
heat                    return TOKHEAT;
on|off                  yylval=!strcmp(yytext,"on"); return STATE;
target                  return TOKTARGET;
temperature             return TOKTEMPERATURE;
\n                      /* ignore end of line */;
[ \t]+                  /* ignore whitespace */;
%%
</programlisting>

      <para>Comme vous pouvez le constater, nous appelons atoi() sur yytext,
      et plaçons le résultat dans yyval, où YACC peut le lire. Nous faisons à
      peu près la même chose pour le match STATE, nous le comparons à 'on', et
      initialisons yylval à 1 si c'est égal. Notez qu'avoir deux match separés
      pour 'on' et 'off' dans lex produirai un code plus rapide, mais j'ai
      voulu montrer une action plus complexe pour changer.</para>

      <para>Maintenant, nous devont apprendre YACC à le supporter. Ce qui est
      appellé yylval avec Lex est appelé différemment avec YACC. Examinons la
      règle réglant la nouvelle temperature cible: </para>

      <programlisting>
target_set: 
        TOKTARGET TOKTEMPERATURE NUMBER
        {
                printf("\tTemperature set to %d\n",$3);
        }
        ;
</programlisting>

      <para>Pour accéder à la valeur de la troisième partie de la règle (cad,
      NUMBER), nous avons besoin d'utiliser $3. Quelque soit le moment du
      retour de yylex(), les contenus de yylval sont attaché au terminal, qui
      peuvent être atteint par le <emphasis role="bold">$-constructeur. &lt;-
      je ne suis pas sur du sens</emphasis></para>

      <para>Pour aller plus loin, observons la nouvelle règle du 'heat
      switch':</para>

      <programlisting>
heat_switch:
        TOKHEAT STATE
        {
                if($2)
                        printf("\tHeat turned on\n");
                else
                        printf("\tHeat turned off\n");
        }
        ;
</programlisting>

      <para>Si vous lancez maintenant l'exemple5, il prend en compte
      correctement ce que vous avez entré.</para>
    </section>

    <section>
      <title>Analyser un fichier de configuration</title>

      <para>Rappelons une partie du fichier de configuration que nous avons vu
      plus haut:</para>

      <programlisting>
zone "." {
        type hint;
        file "/etc/bind/db.root";
};
</programlisting>

      <para>Souvenez vous que nous avons déjà écrit un Lexer pour ce fichier.
      Tout ce dont nous avons besoin maintenant c'est d'écrire la grammaire de
      YACC et modifier l'analyseur lexical (aussi appelé Lexer) pour qu'il
      renvoi les données dans un format compréhensible pour YACC.</para>

      <para>Dans l'analyseur lexicalde l'exemple6, nous avons :</para>

      <programlisting>
%{
#include &lt;stdio.h&gt;
#include "y.tab.h"
%}

%%

zone                    return ZONETOK;
file                    return FILETOK;
[a-zA-Z][a-zA-Z0-9]*    yylval=strdup(yytext); return WORD;
[a-zA-Z0-9\/.-]+        yylval=strdup(yytext); return FILENAME;
\"                      return QUOTE;
\{                      return OBRACE;
\}                      return EBRACE;
;                       return SEMICOLON;
\n                      /* ignore EOL */;
[ \t]+                  /* ignore whitespace */;
%%
</programlisting>

      <para>Si vous observez attentivement, vous pouvez voir que yylval est
      différent ! Nous n'attendons plus de lui d'être un entier, mais nous
      acceptons le fait que ce soit un char *. Dans un but de simplicité, nous
      utilisons strdup et gaspillons beaucoup de ressource mémoires. Veuillez
      noter que cela peut ne pas être un problème dans beaucoup de cas,
      lorsque par exemple vous n'avez besoin d'analyser qu'un fichier, puis de
      quitter.</para>

      <para>Nous souhaitons stocker des chaînes de caractère, car nous ne
      travaillons presque qu'avec des noms : nom de fichiers et noms de zone?.
      Plus tard, dans un autre chapitre, nous expliquerons comment traiter
      différents types de données.</para>

      <para>Pour indiquer à YACC le nouveau type de yylval, nous ajoutons
      cette ligne à l'en-tête de notre grammaire YACC:</para>

      <programlisting>
#define YYSTYPE char *
</programlisting>

      <para>La grammaire elle-même est encore une fois plus compliquée. Nous
      la découpons en parts pour la rendre plus digeste:</para>

      <programlisting>
commands:
        |        
        commands command SEMICOLON
        ;


command:
        zone_set 
        ;

zone_set:
        ZONETOK quotedname zonecontent
        {
                printf("Complete zone for '%s' found\n",$2);
        }
        ;
</programlisting>

      <para>Ceci est l'introduction, comprenant la racine récursive
      précédemment citée. Veuillez noter que nous précisons que chaque
      commande se termine par un ;. (et les commandes sont donc séparées par
      des ;). Nous définissons un type de commande : 'zone_set'. Elle consiste
      en un symbole ZONE (le mot 'zone'), suivit par un 'quotedname' et le
      'zone content'. Ce 'zonecontent ' débute simplement :</para>

      <programlisting>
zonecontent:
        OBRACE zonestatements EBRACE 
</programlisting>

      <para>Il a besoin de commencer avec un OBRACE, un crochet ouvert {. Puis
      suit les 'zonestatement's, suivits par un EBRACE, crochet fermé }.
      </para>

      <programlisting>
quotedname:
        QUOTE FILENAME QUOTE
        {
                $$=$2;
        }
</programlisting>

      <para>Cette section définit ce qu'est un quotedname : un FILENAME (nom
      de fichier) entre QUOTEs (guillemets). Puis il indique quelque chose de
      spécial: la valeur d'un symbole 'quotedname' est la valeur du FILENAME.
      Cela signifie que la valeur du quoted name est le nom du fichier sans
      les quotes</para>

      <para>C'est ce que fait la commande magique '$$=$2;' . Elle dit : ma
      valeur est la valeur de ma seconde partie. Alors que le quoted name est
      désormais referencé par d'autres règles, et que vous accédez à sa valeur
      grâce au <emphasis role="bold">$-constructeur</emphasis>, vous voyez la
      valeur que nous avons fixé ici avec $$=$2.</para>

      <note>
        <para><emphasis role="bold"><emphasis>Cette grammaire bute sur les
        noms de fichiers ne comportant pas de '.' ou de '/'
        </emphasis></emphasis></para>
      </note>

      <programlisting>
zonestatements:
        |
        zonestatements zonestatement SEMICOLON
        ;

zonestatement:
        statements
        |
        FILETOK quotedname 
        {
                printf("A zonefile name '%s' was encountered\n", $2);
        }
        ;
</programlisting>

      <para>Il s'agit d'une instruction générale qui détecte tous les types
      d'instructions à l'intérieur des blocs 'zone'. Nous apercevons ici
      encore de la récursivité.</para>

      <programlisting>
block: 
        OBRACE zonestatements EBRACE SEMICOLON
        ;

statements:
        | statements statement
        ;

statement: WORD | block | quotedname
</programlisting>

      <para>Ceci définit un bloc et les instructions qui peuvent être trouvée
      à l'intérieur.</para>

      <para>Lorsque l'on exécute le tout, la sortie ressemble à cela : </para>

      <screen>
$ ./example6
zone "." {
        type hint;
        file "/etc/bind/db.root";
        type hint;
};
A zonefile name '/etc/bind/db.root' was encountered
Complete zone for '.' found
</screen>
    </section>
  </section>

  <section>
    <title>Faire un Parseur en C++</title>

    <para>Bien que Lex &amp; YACC soient antérieurs à C++, il est possible de
    générer un parseur C++. Flex comprends une option pour générer un Lexer
    C++, mais nous ne l'utiliserons pas, car YAXX ne sait pas comment
    l'utiliser directement.</para>

    <para>Ma méthode préférée pour créer un parseur C++ est de faire générer à
    Lex un fichier C clair, et de laisser YACC générer le code C++. Lorsque
    liez ensuite votre application, vous pouvez avoir quelques problèmes car
    le code C++ fournit par défaut ne sera pas capable de trouver les
    fonctions C, sauf si vous avez indiqué que ces fonction sont du C
    externe.</para>

    <para>Pour faire cela, faites un en-tête C dans YACC, comme cela:</para>

    <programlisting>
extern "C"
{
        int yyparse(void);
        int yylex(void);  
        int yywrap()
        {
                return 1;
        }

}
</programlisting>

    <para>Si vous voulez déclarer ou changer yydebug, vous devez maintenant le
    faire comme ceci:</para>

    <programlisting>
extern int yydebug;

main()
{
        yydebug=1;
        yyparse();
}
</programlisting>

    <para>Cela est du à la définition d'une règle en C++, qui ne permet pas
    plusieurs définitions de yydebug.</para>

    <para>Vous pouvez aussi avoir besoin de répéter le #define de YYSTYPE dans
    votre ficher Lex à cause du vérificateur de type strict de C++.</para>

    <para>Pour compiler, faites quelque chose comme ceci :</para>

    <screen>
lex bindconfig2.l
yacc --verbose --debug -d bindconfig2.y -o bindconfig2.cc
cc -c lex.yy.c -o lex.yy.o
c++ lex.yy.o bindconfig2.cc -o bindconfig2 
</screen>

    <para>A cause de l'option -o, y.tab.h est désormais appelé
    bindconfig2.cc.h, donc prenez le en compte.</para>

    <para>Pour résumer: ne vous embêtez pas à compiler votre lexer en C++,
    laissez le en C. Faites votre parseur en C++ et expliquez à votre
    compilateur que certaines fonctions sont des fonctions C avec des
    instructions externes.</para>
  </section>

  <section>
    <title>Comment fonctionnent Lex et YACC en détail</title>

    <para>Dans le fichier YACC, vous écrivez votre propre fonction main(), qui
    appelle yyparse() à un certain moment. La fonction yyparse()est créée pour
    vous par YACC, et finit dans y.tab.c.</para>

    <para>yyparse() lit un flux de symboles/paires de valeurs depuis yylex() ,
    qui doit être alimenté. Vous pouvez coder cette fonction vous même, ou
    laisser Lex le faire pour vous. Dans nos exemples, nous avons choisit de
    laisser ce travail à Lex.</para>

    <para>Ce yylex() écrit par Lex lit les caractères depuis un FILE* file
    pointer appellé yyin. Si vous ne définissez pas yyin, il est définit par
    défaut sur l'entrée standard. <emphasis role="bold">It outputs to yyout,
    which if unset defaults to stdout.</emphasis> Vous pouvez aussi modifier
    yin dans la fonction yywrap() qui est appelée à la fin d'un fichier. Elle
    vous permet d'ouvrir un autre fichier et de continuer le parsing.</para>

    <para>Si c'est le cas, faites lui retourner 0. Si vous voulez finir le
    parsing par ce fichier, faites lui retourner 1.</para>

    <para>Chaque appel à yylex() retourne une valeur entière qui représente un
    type de jeton. Cela indique à YACC quel type de jeton est lu. Le jeton
    peut éventuellement avoir une valeur, qui devra être placée dans la
    variable yyval.</para>

    <para>Par défaut yylval est du type int, mais vous pouvez le surcharger
    depuis le fichier YACC en redéfinissant #define YYSTYPE.</para>

    <para>Le lexer doit être capable d'accéder à yylval. Pour faire cela, il
    doit être déclaré dans le champ du lexer comme une variable externe. Le
    YACC original omet de le faire, donc vous devrez ajoutez la ligne suivante
    à votre lexer: extern YYSTYPE yyval; , juste après le #include
    &lt;y.tab.h&gt;.</para>

    <programlisting>
extern YYSTYPE yylval;
</programlisting>

    <para>Bison, que la plupart des gens utilise, le fait pour vous
    automatiquement. </para>

    <section>
      <title>Valeurs des symboles</title>

      <para>Comme dit précédemment, yylex() a besoin de renvoyer le type de
      jeton rencontré, et de placer sa valeur dan yylval. Lorsque ces jetons
      sont définits avec la commande %token, il leur est assigné un
      identifiant numérique commençant à 256.</para>

      <para>A cause de cela, il est possible d'avoir tous els caractères ascii
      comme jeton. Imaginons que vous écriviez une calculatrice, jusqu'à
      maintenant, nous aurions écrit le lexer comme ceci:</para>

      <programlisting>
[0-9]+          yylval=atoi(yytext); return NUMBER;
[ \n]+          /* eat whitespace */;
-               return MINUS;
\*              return MULT; 
\+              return PLUS;
...
</programlisting>

      <para> Notre grammaire YACC aurait donc contenu suivant:</para>

      <programlisting>
        exp:    NUMBER 
                |
                exp PLUS exp
                |
                exp MINUS exp
                |
                exp MULT exp
</programlisting>

      <para>Tout ceci est compliqué pour pas grand chose. En utilisant les
      caractères comme abréviations d'identifiants numériques de jetons, nous
      pouvons réécrire notre lexer comme ceci :</para>

      <programlisting>
[0-9]+          yylval=atoi(yytext); return NUMBER;
[ \n]+          /* eat whitespace */;
.               return (int) yytext[0];
</programlisting>

      <para><emphasis role="bold">This last dot matches all single otherwise
      unmatched characters. &lt;- Cette version ne matche pas les caractères
      seuls ou non matchés. Je n'arrive pas à reformuler mais en gros y'a pas
      de match par default ?</emphasis></para>

      <para>Notre grammaire YACC sera donc:</para>

      <programlisting>
        exp:    NUMBER 
                |
                exp '+' exp
                |
                exp '-' exp
                |
                exp '*' exp
</programlisting>

      <para>Cette version est beaucoup plus courte et beaucoup plus évidente.
      Vous n'avez pas besoin de déclarer ces symboles ascii avec %token dans
      l'en-tête, ils sont prêts à l'emploi.</para>

      <para>Un autre avantage avec cette construction est que Lex Lex va
      désormais matcher tout ce que nous lui envoyons – en évitant le
      comportement par défaut qui est de répéter les entrée non matchées vers
      la sortie standard. Si un utilisateur de la calculatrice utilise ^, par
      exemple, il va désormais générer une erreur de parsing, au lieu d'être
      renvoyé vers la sortie standard.</para>
    </section>

    <section>
      <title>Récursivité: 'Droit est maladroit '</title>

      <para>La récursivité est un aspect vital de YACC. Sans elle, vous ne
      pouvez pas spécifier que ce fichier consiste en une séquence de
      commandes ou d'instructions indépendantes.YACC ne s'intéresse qu'a la
      première règle, ou celle désignée comme règle de départ, par le symbole
      '%start'.</para>

      <para>La récursivité dans YACC existe en deux tendances : gauche ou
      droite. La récursivité à gauche qui est celle que vous devriez utiliser
      la plupart du temps, ressemble à ça:</para>

      <programlisting>
commands: /* empty */
        |
        commands command
</programlisting>

      <para>Cela signifie: une commande est soit vide, soit plusieurs
      commandes, suivies par une commande. La manière dont YACC travaille
      signifie qu'il peut désormais séparer facilement des groupes de
      commandes et les réduire.</para>

      <para>Comparons cela à la récursivité à droite, qui de manière plutôt
      confuse paraît meilleure aux yeux de beaucoup:</para>

      <programlisting>
commands: /* empty */
        |
        command commands
</programlisting>

      <para>Mais c'est très coûteux. Si on l'utilise comme règle %start, elle
      nécessite que YACC conserve toutes les commandes dans la file sur le
      tas, ce qui peut prendre beaucoup de ressources mémoires. Utilisez donc
      quoi qu'il arrive la récursivité à gauche lorsque vous analysez de
      longues instructions, comme des fichiers entiers. Il est parfois
      difficile d'éviter la récursivité à droite, mais si vos instructions ne
      sont pas trop longues, il est naturel d'utiliser la récursivité à
      gauche.</para>

      <para>Si vous quelque chose qui termine (et donc qui sépare) vos
      commandes, la Récursion à droite paraît très naturelle, mais reste très
      coûteuse:</para>

      <programlisting>
commands: /* empty */
        |
        command SEMICOLON commands
</programlisting>

      <para>La manière adroite de programmer ceci est d'utiliser la
      récursivité à gauche (je n'ai trouvé cela tout seul non plus):</para>

      <programlisting>
commands: /* empty */
        |
        commands command SEMICOLON
</programlisting>

      <para>Les versions plus anciennes de ce guide pratique utilisaient 
      par erreur la
      Récursion à droite. Markus Triska nous a gentiment informé à ce
      sujet.</para>
    </section>

    <section>
      <title>Plus loin avec yylval : %union</title>

      <para>Actuellement, nous avons besoin de définir LE type yylval. Ce
      n'est cependant pas toujours approprié. dans de nombreux cas nous avons
      besoin de pouvoir utiliser plusieurs types de données. Retournons sur
      notre thermostat fictif, nous souhaitons peut être être capable de
      choisir un heater pour le contrôler, comme ceci.</para>

      <programlisting>
heater mainbuiling
        Selected 'mainbuilding' heater
target temperature 23
        'mainbuilding' heater target temperature now 23
</programlisting>

      <para>Cela demande à yylval d'être une union, qui peut supporter les
      strings et les entiers – mais pas simultanément.</para>

      <para>Souvenez vous que nous avons précédemment dit à YACC de quel type
      yylval est supposé être en définissant YYSTYPE. Il serai concevable de
      définir YYSTYPE ainsi comme une union, mais YACC a une meilleur méthode
      pour faire cela: les instructions %union.</para>

      <para>A partir de l'exemple 4, nous écrivons maintenant la grammaire
      YACC de l'exemple 7. Tout d'abord l'introduction:</para>

      <programlisting>
%token TOKHEATER TOKHEAT TOKTARGET TOKTEMPERATURE

%union 
{
        int number;
        char *string;
}

%token &lt;number&gt; STATE
%token &lt;number&gt; NUMBER
%token &lt;string&gt; WORD
</programlisting>

      <para>Nous définissons notre union, qui contient seulement un nombre et
      un string. Puis en utilisant un une syntaxe étendue de %token nous
      expliquons à YACC à quelle partie de l'union chaque jeton doit
      accéder.</para>

      <para>Dans ce cas, nous laissons le symbole STATE utiliser un entier
      comme précédemment. Il en va de même pour le symbole NUMBER, que nous
      utilisons pour lire les températures.</para>

      <para>Le symbole WORD est lui par contre nouveau, et est déclaré pour
      avoir besoin d'un string.</para>

      <para>Le fichier Lexer change lui aussi un petit peu:</para>

      <programlisting>
%{
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include "y.tab.h"
%}
%%
[0-9]+                  yylval.number=atoi(yytext); return NUMBER;
heater                  return TOKHEATER;
heat                    return TOKHEAT;
on|off                  yylval.number=!strcmp(yytext,"on"); return STATE;
target                  return TOKTARGET;
temperature             return TOKTEMPERATURE;
[a-z0-9]+               yylval.string=strdup(yytext);return WORD;
\n                      /* ignore end of line */;
[ \t]+                  /* ignore whitespace */;
%%
</programlisting>

      <para>Comme vous pouvez le voir, nous n'accédons plus directement à
      yyval directement, nous ajoutons un suffixe indiquant à quelle partie
      nous souhaitons accéder. Nous n'avons cependant pas besoin de le faire
      dans la grammaire YACC, car YACC effectue le travail pour nous:</para>

      <programlisting>
heater_select:
        TOKHEATER WORD
        {
                printf("\tSelected heater '%s'\n",$2);
                heater=$2;
        }
        ;
</programlisting>

      <para>A cause de de la déclaration %token au dessus, YACC choisit
      automatiquement la partie 'string' dans notre union. Notez aussi que
      nous stockons une copie de $2 qui est plus tard utilisée pour indiquer à
      l'utilisateur à quel heater il envoie la commande:</para>

      <programlisting>
target_set:
        TOKTARGET TOKTEMPERATURE NUMBER
        {
                printf("\tHeater '%s' temperature set to %d\n",heater,$3);
        }
        ;
</programlisting>

      <para>Pour plus de détails, Consultez l'exemple 7.y.</para>
    </section>
  </section>

  <section>
    <title>Déboguage</title>

    <para>Particuliermeent lorsque l'on apprends, il est nécessaire d'avoir
    des outils de déboguage. Heureusement, YACC peut fournir énormément
    d'informations. Ces informations sont fournies au prix de temps système,
    vous aurez donc besoin d'interrupteurs pour les activer.</para>

    <para>Lorsque vous compilez votre grammaire, ajoutez --debug et –verbose à
    votre ligne de commande. Dans votre l'en-tête C de votre grammaire ,
    ajoutez :</para>

    <programlisting>
int yydebug=1;
</programlisting>

    <para>Cela générera le fichier 'y.output' qui détaille l'automate qui a
    été crée.</para>

    <para>Lorsque vous lancez le binaire généré, il renverra énormément
    d'informations sur ce qui se passe. Cela inclus dans quel état se trouve
    l'automate et quels symboles sont en trains d'être lus.</para>

    <para>Peter jinks a écrit une page sur le <ulink
    url="http://www.cs.man.ac.uk/~pjj/cs2121/debug.html">déboguage</ulink> qui
    contient quelques erreurs classiques et comment les résoudre.</para>

    <section>
      <title>L'automate à état finis</title>

      <para>Sous le capot, votre analyseur syntaxique YACC fonctionne comme un
      automate fini. Comme le nom l'indique, cet automate (ou machine à états
      finis) peut se trouver dans différents états. Il y a ensuite des règles
      qui gouvernent ces transitions d'un état à l'autre. Tout débute avec la
      règle 'racine' mentionnée plus tôt.</para>

      <para>Pour citer la sortie de l'exemple 7:</para>

      <programlisting>
state 0

    ZONETOK     , and go to state 1

    $default    reduce using rule 1 (commands)

    commands    go to state 29
    command     go to state 2
    zone_set    go to state 3
</programlisting>

      <para><emphasis role="bold">By default, this state reduces using the
      'commands' rule. This is the aforementioned recursive rule that defines
      'commands' to be built up from individual command statements, followed
      by a semicolon, followed by possibly more commands.</emphasis></para>

      <para><emphasis role="bold">This state reduces until it hits something
      it understands, in this case, a ZONETOK, ie, the word 'zone'. It then
      goes to state 1, which deals further with a zone
      command:</emphasis></para>

      <programlisting>
state 1

    zone_set  -&gt;  ZONETOK . quotedname zonecontent   (rule 4)

    QUOTE       , and go to state 4

    quotedname  go to state 5
</programlisting>

      <para><emphasis role="bold">The first line has a '.' in it to indicate
      where we are: we've just seen a ZONETOK and are now looking for a
      'quotedname'. Apparently, a quotedname starts with a QUOTE, which sends
      us to state 4.</emphasis></para>

      <para><emphasis role="bold">To follow this further, compile Example 7
      with the flags mentioned in the Debugging section.</emphasis></para>
    </section>

    <section>
      <title>7.Conflits : décalage/réduction, réduction/réduction</title>

      <para>A chaque fois que YACC vous informe de la présence de conflits,
      vous pouvez avoir des soucis. Résoudre ces conflits semble un art qui
      peut vous apprendre beaucoup sur votre langage, plus que ce que vous
      n'auriez voulu en savoir.</para>

      <para>Ces problèmes sont liés à l'interprétation de la séquence des
      symboles. Supposons que l'on définisse un langage qui ait besoin
      d'accepter les deux commandes suivantes:</para>

      <programlisting>
delete heater all
delete heater number1
</programlisting>

      <para>Pour ce faire, définissons cette grammaire:</para>

      <programlisting>
        delete_heaters:
                TOKDELETE TOKHEATER mode
                {
                        deleteheaters($3);
                }
        
        mode:   WORD

        delete_a_heater:
                TOKDELETE TOKHEATER WORD
                {
                        delete($3);
                }
</programlisting>

      <para>Vous devez déjà sentir les ennuis arriver. L'automate commence par
      lire le mot 'delete' puis doit décider de la transition en se basant sur
      le symbole suivant. Le symbole suivant peut aussi bien être un 'mode',
      spécifiant comment supprimer les 'heaters', ou le nom d'un 'heater' à
      supprimer. </para>

      <para>Cependant le problème est que pour les deux commandes, le symbole
      suivant sera un 'WORD'. YACC n'a par conséquent aucune idée de ce qu'il
      doit faire. Cela conduit à une alerte 'réduction/réduction' et une
      seconde alerte : le n&oelig;ud delete_a_heater ne sera jamais atteint.</para>

      <para>Dans ce cas, le conflit est facilement résolu en renommant la
      première commande 'delete heaters all' ou en faisant de ALL un autre
      symbole. Mais parfois c'est plus difficile. Le fichier y.output généré
      lorsque vous lancez YACC avec l'opion –verbose peut être d'une aide
      formidable.</para>
    </section>
  </section>

  <section>
    <title>Lectures pour approfondir</title>

    <para>GNU YACC (Bison) est fournit avec un fichier info (.info) très
    intéressant qui documente très bien la syntaxe YACC. Il ne mentionne Lex
    qu'une seule fois, mais sinon il est très bon. Vous pouvez lire les
    fichiers .info avec Emacs ou avec l'outil très bien fait 'pinfo'. Il est
    aussi disponible sur le site de GNU : <ulink
    url="http://www.gnu.org/manual/bison/">BISON Manual</ulink>.</para>

    <para>Flex est fournit avec une page de man qui est très utile si vous
    avez déjà une idée approximative de ce que Flex fait. Le <ulink
    url="http://www.gnu.org/manual/flex/">Flex Manual</ulink> est aussi
    disponible en ligne.</para>

    <para>Après cette introduction à Lex et YACC, vous pouvez avoir besoin de
    plus d'informations. Je n'ai pas encore lu ces livres, mais ils semblent
    assez bon:</para>

    <variablelist>
      <varlistentry>
        <term>Bison-The Yacc-Compatible Parser Generator</term>

        <listitem>
          <para>Par Charles Donnelly et Richard Stallman. Un lecteur d'<ulink
          url="http://www.amazon.com/exec/obidos/ASIN/0201100886/ref=sim_books/002-7737249-1404015">Amazon</ulink>
          le trouve très utile.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Lex &amp; Yacc</term>

        <listitem>
          <para>Par John R. Levine, Tony Mason et Doug Brown. Considéré comme
          une référence sur le sujet, bein qu'un peu vieux. Commentaires sur
          Amazon.</para>
        </listitem>
      </varlistentry>

      <varlistentry>
        <term>Compilers : Principles, Techniques, and Tools</term>

        <listitem>
          <para>par Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman. Le 'Dragon
          Book'. De 1985 et ils continuent de le réimprimer. Considéré comme
          la base sur la construction de compilateurs.. <ulink
          url="http://www.amazon.com/exec/obidos/ASIN/0201100886/ref=sim_books/002-7737249-1404015">Amazon</ulink>.</para>
        </listitem>
      </varlistentry>
    </variablelist>

    <para>Thomas Niemann a écrit un document expliquant comment écrire des
    compilateurs et des calculatrices avec Lex et YACC. Vous pouvez le trouver
    <ulink
    url="http://epaperpress.com/lexandyacc/index.html">ici</ulink>.</para>

    <para>La newsgroup modérée comp.compilers peu aussi être très utile, mais
    gardez à l'esprit que les gens là bas ne sont pas une hotline dédiée aux
    parsers. Avant de poster, lisez leur <ulink
    url="http://compilers.iecc.com/">page</ulink> et plus spécialement la
    <ulink url="http://compilers.iecc.com/faq.txt">FAQ</ulink>.</para>

    <para>Lex - A Lexical Analyzer Generator par M. E. Lesk and E. Schmidt est
    l'une des sources de référence. Il peut être trouvé <ulink
    url="http://www.cs.utexas.edu/users/novak/lexpaper.htm">ici</ulink>.</para>

    <para>YACC: Yet Another Compiler Compiler par Stephen C. Johnson est l'une
    des sources de référence. Il peut être trouvé ici. Il contient des astuces
    sur le style.</para>
  </section>

  <section>
    <title>Remerciements</title>

    <itemizedlist>
      <listitem>
        <para>Pete Jinks &lt;pjj%cs.man.ac.uk&gt;</para>
      </listitem>

      <listitem>
        <para>Chris Lattner &lt;sabre%nondot.org&gt;</para>
      </listitem>

      <listitem>
        <para>John W. Millaway &lt;johnmillaway%yahoo.com&gt;</para>
      </listitem>

      <listitem>
        <para>Martin Neitzel &lt;neitzel%gaertner.de&gt;</para>
      </listitem>

      <listitem>
        <para>Sumit Pandaya &lt;sumit%elitecore.com&gt;</para>
      </listitem>

      <listitem>
        <para>Esmond Pitt &lt;esmond.pitt%bigpond.com&gt;</para>
      </listitem>

      <listitem>
        <para>Eric S. Raymond</para>
      </listitem>

      <listitem>
        <para>Bob Schmertz &lt;schmertz%wam.umd.edu&gt;</para>
      </listitem>

      <listitem>
        <para>Adam Sulmicki &lt;adam%cfar.umd.edu&gt;</para>
      </listitem>

      <listitem>
        <para>Markus Triska &lt;triska%gmx.at&gt;</para>
      </listitem>

      <listitem>
        <para>Erik Verbruggen &lt;erik%road-warrior.cs.kun.nl&gt;</para>
      </listitem>

      <listitem>
        <para>Gary V. Vaughan &lt;gary%gnu.org&gt; (read his awesome <ulink
        url="http://sources.redhat.com/autobook">Autobook</ulink>)</para>
      </listitem>

      <listitem>
        <para><ulink url="http://vanderwijk.info">Ivo van der Wijk</ulink>
        (<ulink url="http://www.amaze.nl">Amaze Internet</ulink>)</para>
      </listitem>
    </itemizedlist>
  </section>
</article>
Heberge par Ikoula