texlive[50933] Master: apprendre-a-programmer-en-tex (27apr19)

commits+karl at tug.org commits+karl at tug.org
Fri May 3 00:34:53 CEST 2019


Revision: 50933
          http://tug.org/svn/texlive?view=revision&revision=50933
Author:   karl
Date:     2019-05-03 00:34:52 +0200 (Fri, 03 May 2019)
Log Message:
-----------
apprendre-a-programmer-en-tex (27apr19)

Modified Paths:
--------------
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/libexec/ctan2tds
    trunk/Master/tlpkg/tlpsrc/collection-langfrench.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/README
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/cover/
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/cover/couverture.pdf
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/libertine-legacy.zip
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/linlibmonoc.zip
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/apprendre-a-programmer-en-tex.pdf
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/apprendre-a-programmer-en-tex.tex
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/mandelbrot.pdf
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/mandelbrot.tex
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/pg0001.pdf
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/pg0002.pdf
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/pg0003.pdf
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/progtexmacro.tex
    trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/vignette.png
    trunk/Master/tlpkg/tlpsrc/apprendre-a-programmer-en-tex.tlpsrc

Added: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/README
===================================================================
--- trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/README	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/README	2019-05-02 22:34:52 UTC (rev 50933)
@@ -0,0 +1,162 @@
+-------------------------------- Avant propos ---------------------------------
+
+Ceci est le fichier LISEZMOI du livre « Apprendre à programmer en TeX »
+
+Tous les fichiers fournis dans ce paquet sont sous licence « LPPL v1.2 »
+
+Résumé : le présent paquet contient tous les fichiers permettant de compiler le
+         livre « Apprendre à programmer en TeX ». Il n'est pas nécessaire
+         d'effectuer la compilation pour obtenir les fichiers de sortie puisque
+         ceux-ci sont également fournis :
+             - apprendre-a-programmer-en-tex.pdf
+             - progtexcode.txt
+
+---------------------------------- Foreword -----------------------------------
+
+This is the README file of the book "Apprendre à programmer en TeX"
+
+All the files of this bundle are under "LPPL v1.2" licence
+
+Abstract: this package contains all the files needed to compile the book
+          "Apprendre à programmer en TeX". It is not necessary to perform a
+          compilation to obtain the output files since they are also provided:
+              - apprendre-a-programmer-en-tex.pdf
+              - progtexcode.txt
+
+The text below is available in French only.
+
+-------------------------------------------------------------------------------
+
+I) Prendre le large
+
+Dès le début, c'était prévu après 4 ans grand maximum : libérer le code source
+du livre et par la même occasion, en faire don à la communauté LaTeX. J'ai bien
+conscience que les 4 ans sont passé depuis un bon moment, et c'est donc avec un
+léger retard que je me décide à agir. Tout le « Matériel » de ce livre (code
+source, fichiers pdf, fichiers générés par la compilation, fichiers nécessaires
+à la compilation) va enfin prendre l'air et naviguer de par le monde via
+internet, ce qui sera bien plus profitable que de dormir au fin fond d'un
+répertoire de mon disque dur.
+
+
+
+II) Conséquences
+
+1) La première conséquence est, je l'espère en secret, que davantage
+d'utilisateurs de LaTeX oseront jeter un œil à ce livre et s'essaieront à la
+programmation !
+
+2) La deuxième conséquence est que la licence change. Tout le Matériel se
+trouve désormais sous la « LaTeX project public license » (LPPL) version 1.2,
+mais ce changement implique la chose suivante : il n'est plus possible
+d'utiliser dans le Matériel la police à chasse fixe « Luximono » qui était
+employée dans le livre, car elle n'est pas sous licence libre.
+
+Faire un choix de police de remplacement n'a pas été facile mais finalement,
+LinuxLibertineMono a été adoptée. Cela donne une certaine cohérence à
+l'ensemble puisque la police du texte est LinuxLibertine. Malheureusement,
+telle qu'elle est conçue, son énorme défaut est de chasser beaucoup trop. Il a
+donc fallu la modifier pour créer deux autres polices plus « condensées » :
+
+  a) pour les caractères dans le corps du texte, j'ai créé une police
+  LinuxlibertineMonoTC où les glyphes de LinuxLibertineMonoT ont été, via
+  fontforge, réduits de 75% horizontalement et 92% verticalement. Ce sont,
+  après bien des essais, les coefficients qui lui permettent de s'insérer au
+  mieux (à mon goût) dans le texte, qui donnent une chasse proche de celle de
+  Luximono et qui rendent le gris typographique acceptable ;
+
+  b) pour les codes figurant dans le texte du livre, la police
+  LinuxlibertineMonoTCC a été créée, toujours à partir de LinuxLibertineMonoT,
+  mais les glyphes ont été davantage réduit horizontalement : 67%
+  horizontalement et 92% verticalement.
+
+3) Enfin, la dernière conséquence est que le fichier pdf produit après
+compilation du code source n'est pas exactement celui qui a servi à imprimer le
+livre. Il n'y a que très peu de modifications :
+
+  a) les polices à chasse fixe sont différentes, comme expliqué ci-dessus.
+  Outre les considérations esthétiques sur lesquelles je ne m'étendrai pas,
+  cela ne devrait pas entraîner de modification de la mise en page car la
+  chasse de LinuxlibertineMonoTC est extrêmement proche de celle de Luximono ;
+
+  b) les mentions Luximono sont changées pour LinuxlibertineMonoTC ;
+
+  c) la licence est modifiée (page réelle 6) ;
+
+  d) quelques corrections ont été faites (coquilles, erreurs dans les codes,
+  etc.), mais une infime partie en regard de ce qui resterait à faire !
+
+
+
+III) Compilation
+
+Selon la LPPL 1.2, quiconque peut compiler et distribuer le Matériel sous le
+nom originel, sous réserve qu'aucun changement n'y ait été apporté.
+
+Pour que la compilation puisse être effectuée le plus simplement possible, les
+7 fichiers nécessaires à la compilation se trouvent dans le dossier /source, et
+on y trouve en plus le fichier manderlbrot.tex qui a servi à générer le pdf où
+est dessiné l'ensemble de Mandelbrot à l'aide d'une version modifiée de TeX.
+
+Par ailleurs, toujours par souci de simplicité :
+   - tout le code source est dans un seul fichier « livre.tex », qui est le
+     code source à compiler avec l'exécutable pdflatex ;
+   - seules 3 fontes sont à installer à la main, à savoir LinuxlibertineMonoTC,
+     LinuxlibertineMonoTCC et les fontes de libertine-legacy.
+
+Pour installer ces fontes, il faut aller dans le répertoire /fonts où se
+trouvent des fichiers zippés permettant ces installations. La procédure est
+donnée pour GNU-linux avec TeXlive car je ne connais ni windows ni mikTeX.
+
+1) Installation des fontes "libertine-legacy"
+
+  a) dézipper le fichier libertine-legacy.zip
+
+  b) copier les répertoires /fonts et /tex dans le texmf personnel (permettre
+  d'écrire à l'intérieur des dossiers existants)
+
+  c) aller dans /fonts/maps/dvips/libertine-legacy et lancer dans la console la
+  commande suivante
+          updmap -user --enable map=libertine-legacy.map
+
+2) Installation des fontes LinuxLibertineMono « condensées » :
+
+   a) dézipper le fichier linlibmonoc.zip
+
+   b) copier les répertoires /fonts et /tex dans le texmf personnel (permettre
+   d'écrire à l'intérieur des dossiers existants)
+
+   c) aller dans /fonts/maps/dvips/linlibmonoc et lancer dans la console les
+   deux commandes suivantes :
+          updmap -user --enable map=LinuxLibertineMonoTC.map
+          updmap -user --enable map=LinuxLibertineMonoTCC.map
+
+On peut s'assurer que l'installation s'est correctement déroulée en examinant
+la sortie générée par la commande
+          updmap -user --listmaps
+
+Quoi qu'il en soit, afin que tout ceux qui ne peuvent compiler ce code source
+puissent y accéder, les 2 fichiers dignes d'intérêt qui sont générés à la
+compilation se trouvent dans le répertoire /output, c'est-à-dire :
+  - apprendre-a-programmer-en-tex.pdf (le fichier pdf de sortie)
+  - progtexcode.txt (le fichier qui contient les 454 codes commentés exposés
+    dans les exemples de ce livre).
+
+
+
+IV) Conclusion
+
+Bonne lecture et surtout, prenez du plaisir avec (La)TeX !
+
+N'hésitez pas à poser des questions si certaines choses ne sont pas claires,
+que ce soit à moi directement ou dans un forum où les contributeurs se parlent
+dans la langue de Molière !
+
+Bien évidemment, toute contribution est encouragée, de même que tout retour
+voire un petit remerciement qui vaudra largement le prix auquel est vendu ce
+livre (car il est toujours possible de l'acheter sur lulu.com) ; pour ce faire,
+passer par l'email ou le dépôt sur framagit :
+      unbonpetit at netc.fr
+      https://framagit.org/unbonpetit/apprendre-a-programmer-en-tex/
+
+Christian Tellechea
\ No newline at end of file


Property changes on: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/README
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/cover/couverture.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/cover/couverture.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/cover/couverture.pdf	2019-05-02 22:31:15 UTC (rev 50932)
+++ trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/cover/couverture.pdf	2019-05-02 22:34:52 UTC (rev 50933)

Property changes on: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/cover/couverture.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/libertine-legacy.zip
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/libertine-legacy.zip
===================================================================
--- trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/libertine-legacy.zip	2019-05-02 22:31:15 UTC (rev 50932)
+++ trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/libertine-legacy.zip	2019-05-02 22:34:52 UTC (rev 50933)

Property changes on: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/libertine-legacy.zip
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/linlibmonoc.zip
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/linlibmonoc.zip
===================================================================
--- trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/linlibmonoc.zip	2019-05-02 22:31:15 UTC (rev 50932)
+++ trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/linlibmonoc.zip	2019-05-02 22:34:52 UTC (rev 50933)

Property changes on: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/fonts/linlibmonoc.zip
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/apprendre-a-programmer-en-tex.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/apprendre-a-programmer-en-tex.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/apprendre-a-programmer-en-tex.pdf	2019-05-02 22:31:15 UTC (rev 50932)
+++ trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/apprendre-a-programmer-en-tex.pdf	2019-05-02 22:34:52 UTC (rev 50933)

Property changes on: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/apprendre-a-programmer-en-tex.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt
===================================================================
--- trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt	2019-05-02 22:34:52 UTC (rev 50933)
@@ -0,0 +1,9712 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%                                                                          %%
+%%                        Codes donn\xE9s dans le livre                        %%
+%%                    \xAB Apprendre \xE0 programmer en TeX \xBB                     %%
+%%                                                                          %%
+%%                           Encodage ISO 8859-1                            %%
+%%                                   _____                                  %%
+%%                                                                          %%
+%%                        \xA9 2014 Christian Tellechea                        %%
+%%                                                                          %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Les codes et les macros comment\xE9s donn\xE9s dans ce fichier sont diffus\xE9s sous
+% la licence LaTeX project public license (LPPL) 1.2
+%
+% https://www.latex-project.org/lppl/lppl-1-2/
+% https://www.latex-project.org/lppl/lppl-1-2.txt
+%
+% Attention : ce fichier n'a pas vocation \xE0 \xEAtre compil\xE9
+\endinput
+
+
+****************** Code 1 ******************
+Voici le code en \TeX{} du premier exemple.% ceci est un commentaire
+
+On peut observer l'affichage qu'il produit juste au-dessous !
+****************** Fin code ******************
+
+
+****************** Code 2 ******************
+3 tailles : $% entre en mode math\xE9matique (espaces ignor\xE9s)
+1^{2^3}% 2 est en taille "\scriptstyle" et 3 en taille "\scriptscriptstyle"
+$% fin du mode math
+
+normal $1$, petit $\scriptstyle 2$, tr\xE8s petit $\scriptscriptstyle 3$.
+****************** Fin code ******************
+
+
+****************** Code 3 ******************
+%%% comportement normal %%%
+a) comportement normal :
+Ligne 1
+Ligne 2
+
+Ligne 3
+\medbreak
+b) Aucun caract\xE8re de fin de ligne :
+%%% aucune insertion en fin de ligne %%%
+\endlinechar=-1 
+Ligne 1
+Ligne 2
+
+Ligne 3\endlinechar13
+
+\medbreak
+c) "X" comme caract\xE8re de fin de ligne :
+%%% "X" est ins\xE9r\xE9 \xE0 chaque fin de ligne
+\endlinechar=88
+Ligne 1
+Ligne 2
+
+Ligne 3
+****************** Fin code ******************
+
+
+****************** Code 4 ******************
+a) \number"1A \qquad b) \number"AB3FE \qquad c) \number"78 
+****************** Fin code ******************
+
+
+****************** Code 5 ******************
+a) \number'15 \qquad b) \number'674 \qquad c) \number'46
+****************** Fin code ******************
+
+
+****************** Code 6 ******************
+a) \number`\a \quad %code de caract\xE8re de "a"
+b) \number`\\ \quad % code de caract\xE8re de "\"
+c) \number`\$ \quad % code de caract\xE8re de "$"
+d) \number`\  \quad % code de caract\xE8re de l'espace
+e) \number`\5 \quad % code de caract\xE8re de "5"
+f) \number`\{ \quad % code de caract\xE8re de l'accolade ouvrante
+g) \number`\}       % code de caract\xE8re de accolade fermante
+****************** Fin code ******************
+
+
+****************** Code 7 ******************
+a) \number\catcode`\a \quad %code de cat\xE9gorie de "a"
+b) \number\catcode`\\ \quad % code de cat\xE9gorie de "\"
+c) \number\catcode`\$ \quad % code de cat\xE9gorie de "$"
+d) \number\catcode`\  \quad % code de cat\xE9gorie de l'espace
+e) \number\catcode`\5 \quad % code de cat\xE9gorie de "5"
+f) \number\catcode`\{ \quad % code de cat\xE9gorie de l'accolade ouvrante
+g) \number\catcode`\}       % code de cat\xE9gorie de accolade fermante
+****************** Fin code ******************
+
+
+****************** Code 8 ******************
+Ici, W est une lettre...\par
+\catcode`\W=3 % W devient le signe de bascule en mode math
+Wx+y=3W\par
+$a+b=cW\par
+W2^3=8$\par
+\catcode`\W=11 % W redevient une lettre
+De nouveau, W est une lettre...
+****************** Fin code ******************
+
+
+****************** Code 9 ******************
+$3+4=7$ \par % $ est la bascule math
+\catcode`\$=12 % $ devient un caract\xE8re affichable
+$ s'affiche sans probl\xE8me : $\par
+\catcode`\$=3 % $ redevient la bascule math
+$4+3=7$
+****************** Fin code ******************
+
+
+****************** Code 10 ******************
+Voici les premiers mots de chaque ligne :
+
+\catcode`\ =5 % l'espace est d\xE9ormais de catcode 5
+Cette premi\xE8re ligne sera tronqu\xE9e...
+
+La deuxi\xE8me aussi !
+
+Et la derni\xE8re \xE9galement.
+\catcode`\ =10 % l'espace reprend son catcode
+
+Le comportement normal est restaur\xE9.
+****************** Fin code ******************
+
+
+****************** Code 11 ******************
+\def\foo{Bonjour}% d\xE9finit le texte de remplacement de \foo
+a) \foo Alice.\qquad% espace ignor\xE9
+b) {\foo} Bob.\qquad% espace non ignor\xE9
+c) \foo{} Chris.\qquad% espace non ignor\xE9
+d) \foo\space Daniel.% \space est remplac\xE9 par un espace
+****************** Fin code ******************
+
+
+****************** Code 12 ******************
+\def\startbold{\begingroup \bf}
+\def\stopbold{\endgroup}
+Voici \startbold du texte en gras\stopbold{} et la suite.
+****************** Fin code ******************
+
+
+****************** Code 13 ******************
+\def\foo{foo}
+\begingroup A\aftergroup\foo B\endgroup\par
+{A\aftergroup X\aftergroup\foo B}
+****************** Fin code ******************
+
+
+****************** Code 14 ******************
+1) (un {\it cheval})\par% sans correction d'italique
+2) (un {\it\aftergroup\/cheval})\par% avec correction d'italique
+% on peut d\xE9finir une macro \itacorr qui effectue automatiquement la correction
+\def\itacorr{\it\aftergroup\/}
+3) (un {\itacorr cheval})% avec correction d'italique
+****************** Fin code ******************
+
+
+****************** Code 15 ******************
+\def\bar{Je suis bar.}
+\let\foo\bar % \foo devient \xE9gal \xE0 \bar
+\def\bar{ABC}% \bar est red\xE9finie
+\foo\par% affiche "Je suis bar"
+\bar% affiche "ABC"
+****************** Fin code ******************
+
+
+****************** Code 16 ******************
+Initialement, c'est \TeX.\par
+\let\TeXsauve\TeX% sauvegarde
+\def\TeX{tEx}% red\xE9finition
+Ici, on a modifi\xE9 \TeX.\par
+\let\TeX\TeXsauve% retauration
+De nouveau, c'est \TeX.
+****************** Fin code ******************
+
+
+****************** Code 17 ******************
+\let\sptoken=  %2 espaces avant le "%"
+
+La commande \sptoken compose le paragraphe
+****************** Fin code ******************
+
+
+****************** Code 18 ******************
+{% d\xE9but du groupe
+\catcode`\W=13 \def W{wagons}
+Les W constituent le train.
+}% fin du groupe
+****************** Fin code ******************
+
+
+****************** Code 19 ******************
+\begingroup \catcode`\W=13 
+\gdef\actiw{%
+	\catcode`\W=13 
+	\def W{wagons}}
+\endgroup
+a) Les trains ne sont pas constitu\xE9s de W !\par
+b) \begingroup\actiw Ici, les W forment les trains.\endgroup\par
+c) Ici, les W sont redevenus des lettres.
+****************** Fin code ******************
+
+
+****************** Code 20 ******************
+\begingroup
+	\catcode`\ =13 % rend l'espace actif
+	\gdef\>{\begingroup
+		\catcode`\ =13
+		\def {\hskip5mm\relax}}
+\endgroup
+\let\<=\endgroup
+a) Du texte normal\par
+b) \>Des mots tr\xE8s espac\xE9s\<\par
+c) Du texte normal
+****************** Fin code ******************
+
+
+****************** Code 21 ******************
+\begingroup
+	\catcode`\,=13 \def,{\unskip\string,\space\ignorespaces}
+	La rue assourdissante autour de moi hurlait.
+
+	Longue , mince,en grand deuil  ,  douleur majestueuse ,
+
+	Une femme passa   ,d'une main fastueuse
+
+	Soulevant,balan\xE7ant le feston et l'ourlet ;
+
+\endgroup\medbreak\hfill Charles {\sc Baudelaire}
+****************** Fin code ******************
+
+
+****************** Code 22 ******************
+\begingroup
+	\catcode`\,=13 \def,{\unskip\string, \ignorespaces}
+	\catcode`\^^M=13 \let ^^M\par % rend le retour charriot \xE9gal \xE0 \par
+	La rue assourdissante autour de moi hurlait.
+	Longue , mince,en grand deuil  , douleur majestueuse ,
+	Une femme passa   ,   d'une main fastueuse
+	Soulevant,balan\xE7ant le feston et l'ourlet ;
+\endgroup\medbreak\hfill Charles {\sc Baudelaire}
+****************** Fin code ******************
+
+
+****************** Code 23 ******************
+{% ouvre un groupe
+	\let\AA=a \let\EE=e \let\II=i \let\OO=o \let\UU=u \let\YY=y
+	% sauvegarder avant de modifier le catcode de a et e :
+	\let\lEt=\let \let\cAtcOdE=\catcode
+	\cAtcOdE`\a=13 \lEt a=\EE \cAtcOdE`\e=13 \lEt e=\II
+	\cAtcOdE`\i=13 \lEt i=\OO \cAtcOdE`\o=13 \lEt o=\UU
+	\cAtcOdE`\u=13 \lEt u=\YY \cAtcOdE`\y=13 \lEt y=\AA
+	Ce texte devenu \`a peine reconnaissable montre que le r\'esultat
+	contient des sonorit\'es catalanes, corses ou grecques assez
+	inattendues.
+}% ferme le groupe
+****************** Fin code ******************
+
+
+****************** Code 24 ******************
+{%
+	\let\AA=a \let\lEt=\let \let~=\catcode
+	~`a=13 \lEt a=e ~`e=13 \lEt e=i ~`i=13 \lEt i=o
+	~`o=13 \lEt o=u ~`u=13 \lEt u=y ~`y=13 \lEt y=\AA
+	Ce texte devenu \`a peine reconnaissable...
+}
+****************** Fin code ******************
+
+
+****************** Code 25 ******************
+a) \def\foo{Bonjour}\meaning\foo\par
+b) \let\bar=\foo\meaning\bar\par% \foo est "copi\xE9e" vers \bar
+c) \def\baz{\foo}\meaning\baz\par
+d) \catcode`\W=13 \def W{Wagons}% W est un caract\xE8re actif
+   \meaning W\par
+e) \meaning\def% \def est une primitive
+****************** Fin code ******************
+
+
+****************** Code 26 ******************
+a) \def\foo{
+
+}Signification de \string\foo{} : \meaning\foo
+
+b) Signification de deux retours charriots cons\xE9cutifs : \meaning
+
+****************** Fin code ******************
+
+
+****************** Code 27 ******************
+a) \meaning\relax\par% primitive
+b) \meaning {\par% catcode 1
+c) \meaning }\par% catcode 2
+d) \meaning $\par% catcode 3
+e) \meaning &\par% catcode 4
+g) \meaning #\par% catcode 6
+h) \meaning ^\par% catcode 7
+i) \meaning _\par% catcode 8
+j) \meaning a\par% catcode 11 (une lettre)
+k) \meaning +\par% catcode 12 (caract\xE8re "autre")
+l) \meaning ~\par% catcode 13 (caract\xE8re actif)
+****************** Fin code ******************
+
+
+****************** Code 28 ******************
+\begingroup% dans un groupe
+	\let\*=\meaning% rendre \* \xE9gal \xE0 \meaning
+	\* %<- espace pris en compte
+\endgroup% fermer le groupe
+****************** Fin code ******************
+
+
+****************** Code 29 ******************
+\begingroup
+\catcode`\*0 
+\catcode`\\12 % \ n'est plus un caract\xE8re d'\xE9chappement
+*def*foo{bar}
+*LaTeX{} et la macro *string*foo : *foo.
+
+L'ancien caract\xE8re d'\xE9chappement  "\" et \TeX.
+*endgroup
+****************** Fin code ******************
+
+
+****************** Code 30 ******************
+\def\foo{\bar}
+\begingroup
+a) \escapechar=-1  \meaning\foo\qquad% pas de caract\xE8re d'\xE9chappement
+b) \escapechar=`\@ \meaning\foo\qquad% "@" est le caract\xE8re d'\xE9chappement
+\endgroup
+c) \meaning\foo% caract\xE8re d'\xE9chappement par d\xE9faut
+****************** Fin code ******************
+
+
+****************** Code 31 ******************
+\begingroup
+	\catcode`\|=0 |catcode`|\=11 |catcode`|2=11 |catcode`|1=11 
+	|gdef|1\2\a{foo}
+|endgroup
+Voici la macro : \csname 1\string\2\string\a\endcsname
+****************** Fin code ******************
+
+
+****************** Code 32 ******************
+\newtoks\foo% allocation d'un nouveau registre
+\foo={Bonjour le monde}% assignation
+Contenu du registre {\tt\string\foo} : \the\foo.
+
+\newtoks\bar% allocation d'un autre registre
+\bar=\foo% assigne \xE0 \bar les tokens du registre \foo
+Contenu du registre {\tt\string\bar} : \the\bar.
+****************** Fin code ******************
+
+
+****************** Code 33 ******************
+\def\hello#1#2{Bonjour #1 et #2.\par}% d\xE9finition
+\hello ab% #1=a et #2=b
+\hello a b% #1=a et #2=b
+\hello{foo}{bar}% #1=foo et #2=bar
+\hello foobar% #1=f et #2=o
+% (le reste "obar" est lu apr\xE8s que la macro est termin\xE9e)
+****************** Fin code ******************
+
+
+****************** Code 34 ******************
+\def\tenlist#1#2#3#4#5#6#7#8#9{(#1,#2,#3,#4,#5,#6,#7,#8,#9\endlist}
+\def\endlist#1{,#1)}
+Une liste \tenlist abcdefghij de lettres.
+****************** Fin code ******************
+
+
+****************** Code 35 ******************
+\def\foo#1#2{Bonjour #1 et #2.\par}
+\begingroup\tt% passer en fonte \xE0 chasse fixe
+a) \foo{monsieur}{madame}
+b) \foo{{\bf toi}}{moi}
+c) \foo{}{{}}
+d) \foo{ }{ }
+e) \foo{$\pi$} {$\delta$}
+f) \foo ab
+g) \foo X       Y
+\endgroup% fin de la fonte \xE0 chasse fixe
+****************** Fin code ******************
+
+
+****************** Code 36 ******************
+\def\foo{Programmer  en \TeX {} est   facile}
+\meaning\foo\par
+\def\foo{Program^^6der en   \TeX{} est facile}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 37 ******************
+a) \gobone XY - \secondoftwo XY\par
+b) \gobone{ab}{xy} - \secondoftwo{ab}{xy}\par
+c) \gobone{123}4 - \secondoftwo{123}4\par
+d) \gobone A{BCD} - \secondoftwo A{BCD}
+****************** Fin code ******************
+
+
+****************** Code 38 ******************
+\gobone     {a}{\catcode`\~12 Le <<~>> est un espace ?} Et ici <<~>> ?
+
+\secondoftwo{a}{\catcode`\~12 Le <<~>> est un espace ?} Et ici <<~>> ?
+****************** Fin code ******************
+
+
+****************** Code 39 ******************
+\def\visible{\let\choix=\firstoftwo}
+\def\cache{\let\choix=\secondoftwo}
+\def\?#1{\choix{#1}{...}}%
+\def\interro{J'ai \xE9t\?{\xE9} invit\?{\xE9} \xE0 gout\?{er} chez Max. Apr\xE8s s'\xEAtre
+             bien amus\?{\xE9}, nous avons rang\?{\xE9} et il a fallu rentr\?{er}.}
+Compl\xE9ter avec << \xE9 >> ou << er >> :\par
+\cache\interro\par\medskip
+Correction :\par
+\visible\interro
+****************** Fin code ******************
+
+
+****************** Code 40 ******************
+\def\visible{\let\?=\identity}
+\def\cache{\def\?##1{...}}
+\def\interro{J'ai \xE9t\?{\xE9} invit\?{\xE9} \xE0 go\xFBt\?{er} chez Max. On s'est
+             bien amus\?{\xE9} et ensuite, il a fallu rentr\?{er}.}
+Compl\xE9ter avec << \xE9 >> ou << er >> :\par
+\cache\interro\par\medskip
+Correction :\par
+\visible\interro
+****************** Fin code ******************
+
+
+****************** Code 41 ******************
+\def\makemacro#1#2{\def#1##1{##1 #2}}
+\makemacro\LL{Lamport}
+\makemacro\juin{juin 2014}
+Paris, le \juin{3}.\medbreak
+\LL{Cher Monsieur},\smallbreak
+Vous \xEAtes convoqu\xE9 \xE0 un examen sur \TeX{} le \juin{21} \xE0
+9h00 pr\xE9cise dans le bureau de D. Knuth.\smallbreak
+Veuillez croire, \LL{Monsieur}, en mes sentiments \TeX iens.
+****************** Fin code ******************
+
+
+****************** Code 42 ******************
+\def\showcodes#1{\string#1 : $\number`#1 \rightarrow \number\lccode`#1$}
+\showcodes A\qquad \showcodes B\qquad
+\showcodes a\qquad \showcodes b\qquad \showcodes ^
+****************** Fin code ******************
+
+
+****************** Code 43 ******************
+\lowercase{CACAO foobar}\par
+\lowercase{\def\foo{Bonjour}}% d\xE9finit une commande \foo
+\foo % la commande d\xE9finie pr\xE9c\xE9demment
+****************** Fin code ******************
+
+
+****************** Code 44 ******************
+\begingroup
+	\lccode`A=`* % change le code minuscule de A
+	\lowercase{CACAO ABRACADABRA}\par
+\endgroup
+\lowercase{CACAO ABRACADABRA}
+****************** Fin code ******************
+
+
+****************** Code 45 ******************
+\def\defactive#1{%
+	\catcode`#1=13
+	\begingroup
+	\lccode`~=`#1
+	\lowercase{\endgroup\def~}%
+}
+\begingroup% les modifications restent locales
+	\defactive W{wagons}% d\xE9finit le caract\xE8re actif "W"
+	Les W constituent les trains.
+\endgroup %fermeture du groupe, "W" redevient une lettre
+\par Les W sont des lettres
+****************** Fin code ******************
+
+
+****************** Code 46 ******************
+\defactive W{wagon}
+1) Les W constituent le train.\par
+2) \catcode`W=11 Les W sont des lettres.\par
+3) \catcode`\W=13 Les W constituent-ils le train ?
+****************** Fin code ******************
+
+
+****************** Code 47 ******************
+\def\defactive#1#2{%
+	\catcode`#1=13 % #1 sera actif apr\xE8s la fin du texte de remplacement
+	\begingroup
+	\lccode`~=`#1  % dans \lowercase, changer les ~ (actifs) en "#1", ceux-ci \xE9tant actifs
+	\lowercase{\endgroup\def~}{#2}%
+	}
+\defactive W{Wagon}
+Un W.
+****************** Fin code ******************
+
+
+****************** Code 48 ******************
+\def\defactive#1{%
+	\catcode`#1=13 % #1 sera actif apr\xE8s la fin du texte de remplacement
+	\begingroup
+	\lccode`~=`#1 % dans \lowercase, changer les ~ (actifs) en "#1", ceux-ci \xE9tant actifs
+	\lowercase{\endgroup\def~}%
+	}
+\defactive W{Wagon}
+Un W.
+****************** Fin code ******************
+
+
+****************** Code 49 ******************
+\def\defactive#1#2{%
+	\catcode`#1=13 % #1 sera actif apr\xE8s la fin du texte de remplacement
+	\begingroup
+	\uccode`~=`#1 % dans \uppercase, changer les ~ (actifs) en "#1", ceux-ci \xE9tant actifs
+	\uppercase{\endgroup\def~}{#2}%
+}
+\defactive W{Wagon}
+Un W.
+****************** Fin code ******************
+
+
+****************** Code 50 ******************
+\def\letactive#1{%
+	\catcode`#1=13 % #1 sera actif apr\xE8s la fin du texte de remplacement
+	\begingroup
+	\uccode`~=`#1 % dans \uppercase, changer les ~ (actifs) en "#1", ceux-ci \xE9tant actifs
+	\uppercase{\endgroup\let~}%
+}
+\def\W{wagon}%
+\letactive X\W
+Un X.
+****************** Fin code ******************
+
+
+****************** Code 51 ******************
+\def\litterate#1{% #1=lit le token fronti\xE8re choisi
+	\begingroup% ouvre un groupe pour y faire les modifications
+		\def\do##1{\catcode`##1=12 }% \do change le catcode de son argument \xE0 12
+		\dospecials% rend inoffensifs tous les tokens sp\xE9ciaux
+		\defactive\^^M{\leavevmode\par}% d\xE9finit le retour charriot
+		\letactive#1\endgroup% d\xE9finit #1 qui sera un \endgroup
+		\tt% passe en fonte \xE0 chasse fixe
+}
+essai 1 : \litterate*\foo # #34{ } &_\ *
+\medbreak
+essai 2 : \litterate/une premi\xE8re ligne  ,, >>
+
+un saut de ligne et la seconde --/
+****************** Fin code ******************
+
+
+****************** Code 52 ******************
+\def\litterate#1{% #1=lit le token fronti\xE8re choisi
+	\begingroup% ouvre un groupe pour y faire les modifications
+		\def\do##1{\catcode`##1=12 }% \do change le catcode de son argument \xE0 12
+		\dospecials% rend inoffensifs tous les tokens sp\xE9ciaux
+		\defactive\^^M{\leavevmode\par}% d\xE9finit le retour charriot
+		\defactive\ {\ }% l'espace est actif et devient "\ "
+		\defactive<{\string<{}}\defactive>{\string>{}}% emp\xEAche
+		\defactive-{\string-{}}\defactive`{\string`{}}% les
+		\defactive,{\string,{}}\defactive'{\string'{}}% ligatures
+		\letactive#1\endgroup% #1 sera un \endgroup
+		\tt% passe en fonte \xE0 chasse fixe
+}
+essai 1 : \litterate*\foo # #34{ %} &_\ *
+\medbreak
+essai 2 : \litterate/une premi\xE8re      ligne  ,, >>
+
+un saut de ligne et la seconde --/
+****************** Fin code ******************
+
+
+****************** Code 53 ******************
+\def\baz#1#2#3#{"#1", puis "#2" et enfin "#3".}
+\baz{abc}def{gh}ij
+****************** Fin code ******************
+
+
+****************** Code 54 ******************
+\catcode`\@11
+\long\def\firstto at nil#1#2\@nil{#1}
+\long\def\remainto at nil#1#2\@nil{#2}
+a) \firstto at nil foobar\@nil   \qquad b) \remainto at nil foobar\@nil  \par
+c) \firstto at nil {foo}bar\@nil \qquad d) \remainto at nil {foo}bar\@nil
+****************** Fin code ******************
+
+
+****************** Code 55 ******************
+\catcode`\@=11 % "@" devient une lettre
+\def\rightof#1#2{%
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+	\right at of#1\@nil% appelle la macro auxiliaire o\xF9 #1 est la <chaine>
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{gram}--\par
+--\rightof{Programmation}{on}--
+****************** Fin code ******************
+
+
+****************** Code 56 ******************
+\catcode`\@=11 % "@" devient une lettre
+\def\rightof#1#2{%
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+	\right at of#1\@nil% appelle la macro auxiliaire
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{Gram}
+****************** Fin code ******************
+
+
+****************** Code 57 ******************
+\catcode`\@=11 % "@" devient une lettre
+\def\rightof#1#2{%
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+	\right at of#1#2\@nil% appelle la macro auxiliaire avec le motif #2
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{ti}--\par
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{Gram}--
+****************** Fin code ******************
+
+
+****************** Code 58 ******************
+\catcode`\@=11 % "@" devient une lettre
+\def\gobto@@nil#1\@@nil{}
+\def\rightof#1#2{%
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+	\right at of#1\gobto@@nil#2\gobto@@nil\@@nil\@nil% appelle la macro auxiliaire
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{ti}--\par
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{Gram}--
+****************** Fin code ******************
+
+
+****************** Code 59 ******************
+\catcode`\@=11 % "@" devient une lettre
+
+\def\rightof#1#2{%
+	\ifin{#1}{#2}%
+		{% si #1 contient le #2
+		\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+		\right at of#1\@nil% appelle la macro auxiliaire
+		}%
+		{}% sinon, ne rien faire
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{o}--
+****************** Fin code ******************
+
+
+****************** Code 60 ******************
+\catcode`\@=11
+\def\leftof#1#2{%
+	\def\leftof at i##1#2##2\@nil{##1}% renvoie ce qui est \xE0 gauche de #2
+	\leftof at i #1#2\@nil% ajoute #2 apr\xE8s #1
+}
+\catcode`\@=12
+--\leftof{Programmation}{ram}--\par
+--\leftof{Programmation}{zut}--
+****************** Fin code ******************
+
+
+****************** Code 61 ******************
+\catcode`\@=11
+\def\leftof#1#2{%
+	\def\leftof at i##1#2##2\@nil{\leftof at ii##1#1\@nil}%
+	\def\leftof at ii##1#1##2\@nil{##1}%
+	\leftof at i #1#2\@nil
+}
+\catcode`\@=12 
+--\leftof{Programmation}{ram}--\par
+--\leftof{Programmation}{zut}--
+****************** Fin code ******************
+
+
+****************** Code 62 ******************
+\catcode`\@=11
+\def\rightof#1#2{%
+	\def\rightof at i##1#2##2\@nil{\rightof at ii##2#2\@nil}%
+	\def\rightof at ii##1#2##2\@nil{##1}%
+	\rightof at i#1#2\@nil
+}
+\catcode`\@=12 
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{z}--
+****************** Fin code ******************
+
+
+****************** Code 63 ******************
+\catcode`\@=11
+\def\gobto@@nil#1\@@nil{}
+\def\rightof#1#2{%
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+	\right at of#1\gobto@@nil#2\gobto@@nil\@@nil\@nil% appelle la macro auxiliaire
+}
+\catcode`\@=12
+\rightof{abc{1}def}{c{1}d}% affiche ce qui est \xE0 droite de "c{1}d"
+****************** Fin code ******************
+
+
+****************** Code 64 ******************
+\expandafter\def\csname ab1c\endcsname{Bonjour}
+Texte de remplacement de la macro : \csname ab1c\endcsname
+****************** Fin code ******************
+
+
+****************** Code 65 ******************
+\def\defname#1{\expandafter\def\csname#1\endcsname}
+\defname{ab1c}{Bonjour}
+Texte de remplacement de \litterate|\abc1| : \csname ab1c\endcsname\par
+\def\letname#1{\expandafter\let\csname#1\endcsname}
+\def\foo{abc}\letname{foo1}=\foo% rend la macro "\foo1" \xE9gale \xE0 \foo
+Texte de remplacement de \litterate|\foo1| : \csname foo1\endcsname
+****************** Fin code ******************
+
+
+****************** Code 66 ******************
+ \def\foo{Bonjour}\catcode`@=11
+R\xE9sultat : \firstto at nil\foo\@nil
+\catcode`@=12
+****************** Fin code ******************
+
+
+****************** Code 67 ******************
+\def\foo{Bonjour}\catcode`@=11
+R\xE9sultat : \expandafter\firstto at nil\foo\@nil
+\catcode`@=12
+****************** Fin code ******************
+
+
+****************** Code 68 ******************
+\newtoks\testtoks \testtoks={Bonjour}
+\catcode`@=11
+R\xE9sultat : \expandafter\firstto at nil\the\testtoks\@nil
+\catcode`@=12
+****************** Fin code ******************
+
+
+****************** Code 69 ******************
+\def\foo{bonjour}
+a) \>\csname foo\endcsname< \par
+b) \>\foo< \par
+c) \expandafter\>\foo< \par
+d) \>\foo\foo< \par
+e) \expandafter\>\foo\foo<
+****************** Fin code ******************
+
+
+****************** Code 70 ******************
+\def\foo{Bonjour} \expandafter\>\expandafter\foo\foo<
+****************** Fin code ******************
+
+
+****************** Code 71 ******************
+\def\foo{Bonjour}
+\expandafter\def\expandafter\bar\expandafter{\expandafter\foo\foo}
+\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 72 ******************
+\def\foo{\foo Bonjour}% d\xE9finition r\xE9cursive
+\foo% l'ex\xE9cution provoque un d\xE9passement de la capacit\xE9 de la pile
+****************** Fin code ******************
+
+
+****************** Code 73 ******************
+\long\def\addtomacro#1#2{%
+	\expandafter\def\expandafter#1\expandafter{#1#2}%
+}
+\def\foo{Bonjour}
+\addtomacro\foo{ le monde}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 74 ******************
+\long\def\eaddtomacro#1#2{%
+	\expandafter\addtomacro\expandafter#1\expandafter{#2}%
+}
+\def\foo{Bonjour} \def\world{ le monde}
+\eaddtomacro\foo\world
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 75 ******************
+\long\def\addtotoks#1#2{#1= \expandafter{\the#1#2}}
+\newtoks\bar
+\bar={Bonjour}% met "Bonjour" dans le registre
+\addtotoks\bar{ le monde}% ajoute " le monde"
+\the\bar% affiche le registre
+****************** Fin code ******************
+
+
+****************** Code 76 ******************
+\long\def\eaddtotoks#1#2{\expandafter\addtotoks\expandafter#1\expandafter{#2}}
+\bar={Bonjour}
+\def\macrofoo{ le monde}
+\eaddtotoks\bar\macrofoo
+\the\bar
+****************** Fin code ******************
+
+
+****************** Code 77 ******************
+\def\X{Bonjour} \def\Y{\X}
+\expandafter\expandafter\expandafter\>\Y<
+****************** Fin code ******************
+
+
+****************** Code 78 ******************
+\long\def\swaparg#1#2{#2{#1}}
+\long\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}
+\def\X{Bonjour}
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\>\expsecond{\X}{\X}<
+****************** Fin code ******************
+
+
+****************** Code 79 ******************
+\expsecond{\def\foo}\secondoftwo{A}{B}
+****************** Fin code ******************
+
+
+****************** Code 80 ******************
+\expsecond{\def\foo}{\secondoftwo{A}{B}}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 81 ******************
+\def\exptwoargs#1#2{\expsecond{\expsecond{#1}{#2}}}
+\def\foo{Bonjour}\def\bar{ le monde}
+\def\displaytwoargs#1#2{\detokenize{#1#2}}% affiche tels quels les arguments
+\exptwoargs\displaytwoargs\foo\bar
+****************** Fin code ******************
+
+
+****************** Code 82 ******************
+\def\aa{Bonjour}\def\bb{\aa}
+\def\cc{ le monde}
+\edef\foo{\bb\cc}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 83 ******************
+\def\aa{Bonjour } \def\bb{\aa} \def\cc{le } \def\dd{ monde}
+\edef\ee#1{\bb\cc#1 !!!}
+\meaning\ee\par
+\expandafter\>\ee{\dd}<
+****************** Fin code ******************
+
+
+****************** Code 84 ******************
+\def\foo{123xyz}
+a) signification du 1-d\xE9veloppement d'un \litterate-\noexpand- :
+   \expandafter\meaning\noexpand\foo
+
+b) ex\xE9cution d'un \litterate-\noexpand- : \noexpand\foo% identique \xE0 \relax
+
+c) 1-d\xE9veloppement de \litterate-\noexpand- dans le texte de remplacement de
+   \litterate-\bar- :
+   \expandafter\def\expandafter\bar\expandafter{\noexpand\foo}
+   \meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 85 ******************
+\def\aa{Bonjour}\def\bb{\aa}\def\cc{\bb}
+a) \edef\foo{\aa\noexpand\bb\cc}\meaning\foo  \qquad b) ex\xE9cution : \foo\par
+c) \edef\foo{\aa\noexpand{\aa\cc}}\meaning\foo\qquad d) ex\xE9cution : \foo
+****************** Fin code ******************
+
+
+****************** Code 86 ******************
+\def\aa{Bonjour}\def\bb{Au revoir}
+a) \edef\truc{\aa\noexpand\bb\noexpand\aa\bb}\meaning\truc \par
+b) \edef\truc{\aa\unexpanded{\bb\aa}\bb}\meaning\truc
+****************** Fin code ******************
+
+
+****************** Code 87 ******************
+\def\aa{Bonjour}\def\bb{Au revoir}
+\toks0={\aa\bb}
+\edef\foo{\aa\the\toks0 \bb}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 88 ******************
+\def\aa{Bonjour}
+\protected\def\bb{ le}% \ bb est prot\xE9g\xE9e !
+\def\cc{ monde}
+
+\edef\foo{\aa\bb\cc}
+Signification de \string\foo~: \meaning\foo \par
+Ex\xE9cution de \string\foo~: \foo
+****************** Fin code ******************
+
+
+****************** Code 89 ******************
+\def\aa{Bonjour}
+\protected\def\bb{ le}
+\def\cc{ monde}
+
+\edef\foo{\expandafter\aa\bb\cc}% le \expandafter 1-d\xE9veloppe \bb
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 90 ******************
+\def\foo{Bonjour}% d\xE9finition
+\foo% ex\xE9cution
+****************** Fin code ******************
+
+
+****************** Code 91 ******************
+\def\foo{abc}
+\edef\bar{\def\foo{Bonjour}\foo}
+\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 92 ******************
+\def\foo{abc}
+\edef\bar{\def\noexpand\foo{Bonjour}\noexpand\foo}
+Signification : \meaning\bar\par
+Ex\xE9cution : \bar
+****************** Fin code ******************
+
+
+****************** Code 93 ******************
+\long\def\>#1<{\detokenize{#1}}
+\expandafter\>% provoque le 1-d\xE9veloppement de :
+\csname foo\expandafter\endcsname
+\csname bar\expandafter\endcsname
+\csname wee\expandafter\endcsname
+\csname fin\endcsname<
+****************** Fin code ******************
+
+
+****************** Code 94 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\fin{YY} \def\wee{\weeA} \def\weeA{XX}
+\expandafter\>%
+\csname foo\expandafter\endcsname
+\csname bar\expandafter\expandafter\expandafter\expandafter
+           \expandafter\expandafter\expandafter\endcsname
+\csname wee\expandafter\expandafter\expandafter\endcsname
+\csname fin\endcsname<
+****************** Fin code ******************
+
+
+****************** Code 95 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\fin{YYY} \def\wee{\weeA} \def\weeA{XXX}
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\>%
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\foo
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\bar
+\expandafter\wee\fin<
+****************** Fin code ******************
+
+
+****************** Code 96 ******************
+\chardef\foo65 
+a) |\foo|\qquad % employ\xE9e seule, \foo affiche un A
+b) |\number\foo|\qquad % si TeX lit un nombre, \foo est le nombre 65
+****************** Fin code ******************
+
+
+****************** Code 97 ******************
+\mathchardef\foo4944 
+a) |$\foo$|\qquad % en mode math, affiche le signe "somme" (uniquement en mode maths)
+b) |\number\foo|\qquad % si TeX lit un nombre, \foo est 4944
+****************** Fin code ******************
+
+
+****************** Code 98 ******************
+a) "\romannumeral 27 "\quad
+b) "\romannumeral 4687 "\quad
+c) "\romannumeral 0 "\quad% 0 donc d\xE9veloppement vide
+d) "\romannumeral -2014 "\quad% n\xE9gatif donc d\xE9veloppement vide
+e) \def\foo{7}\def\bar{\foo}%
+   "\romannumeral \foo\foo\bar"\quad% 777
+f) "\romannumeral 1\bar8\foo"\quad% 1787
+g) "\romannumeral 1\bar8 \foo"% 178 (stopp\xE9 par l'espace) puis 7
+****************** Fin code ******************
+
+
+****************** Code 99 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\swaparg#1#2{#2{#1}}
+\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}
+\def\X{Bonjour}
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\>\expsecond\X\X<
+****************** Fin code ******************
+
+
+****************** Code 100 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\swaparg#1#2{0 #2{#1}}% le "0 " stoppe ici le d\xE9veloppement maximal
+\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}
+\def\X{Bonjour}
+\expandafter\>\romannumeral\expsecond\X\X<
+****************** Fin code ******************
+
+
+****************** Code 101 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\swaparg#1#2{#2{#1}}
+\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}
+\def\X{Bonjour}
+\expandafter\>\romannumeral\expsecond{0 \X}\X<
+****************** Fin code ******************
+
+
+****************** Code 102 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\X{Bonjour}
+\catcode`\@=11
+\expandafter\>\romannumeral\expsecond{\z@\X}{\X}<
+\catcode`\@=12
+****************** Fin code ******************
+
+
+****************** Code 103 ******************
+\def\newunivar#1{\def#1[##1]{\csname\string#1[##1]\endcsname}}
+\def\defunivar#1[#2]{\defname{\string#1[#2]}}
+\newunivar\foobar
+\defunivar\foobar[0]{abcd}
+\defunivar\foobar[1]{1 23}
+\defunivar\foobar[3]{XY Z}
+Cellule 0 : \foobar[0]\par
+Cellule 1 : \foobar[1]\par
+Cellule 2 : \foobar[2]\par% cellule non d\xE9finie : \foobar[2] donne \relax
+Cellule 3 : \foobar[3]\bigbreak
+
+\newunivar\client
+\defunivar\client[nom]{M. Raymond {\sc  Tartempion}}
+\defunivar\client[adr]{5 rue de la paix}
+\defunivar\client[cod_post]{75000}
+\defunivar\client[ville]{Paris}
+% fin des d\xE9finitions, affichage de l'adresse :
+\client[nom]\par
+\client[adr]\par
+\client[cod_post] \client[ville]
+****************** Fin code ******************
+
+
+****************** Code 104 ******************
+\newcount\foo \newcount\bar
+\foo=42 \bar=\foo \string\bar\ vaut : \the\bar \par
+\bar=\foo57 \string\bar\ vaut : \number\bar\par
+\bar=2014 \string\bar\ vaut : \romannumeral\bar
+****************** Fin code ******************
+
+
+****************** Code 105 ******************
+\newcount\foo
+\def\fonction#1{%
+  \foo=#1 % assigne l'entier #1 au compteur puis
+  \multiply\foo3 % multiplie par 3
+  \advance\foo-4 % soustrait 4
+  \multiply\foo\foo% \xE9l\xE8ve au carr\xE9 (lmultiplie \foo par lui m\xEAme)
+  \number\foo% enfin, afficher le r\xE9sultat
+}
+a) \fonction5\qquad b) \fonction{-13}
+****************** Fin code ******************
+
+
+****************** Code 106 ******************
+\newcount\foo
+\def\fonction#1{%
+  \foo=#1 \multiply\foo3 \advance\foo-4 \multiply\foo\foo
+  \number\foo}
+\edef\bar{\fonction{5}}%
+a) Signification : \meaning\bar\par
+b) Ex\xE9cution : \bar
+****************** Fin code ******************
+
+
+****************** Code 107 ******************
+a) \number\numexpr2+3*4\relax\qquad
+b) \romannumeral\numexpr2*3\relax\qquad
+c) \number\numexpr(6-2*4)*(1-(2-6))\relax\qquad
+d) \number\numexpr7/4\relax\qquad %7/4 vaut 1,75
+e) \edef\foo{\number\numexpr2+3*4\relax}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 108 ******************
+\number\numexpr3*\numexpr1+2*5\relax+2\relax
+****************** Fin code ******************
+
+
+****************** Code 109 ******************
+\def\fonction#1{\number\numexpr(3*#1-4)*(3*#1-4)\relax}
+a) \fonction5\qquad
+b) \fonction{-13}\qquad
+c) \edef\bar{\fonction5}\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 110 ******************
+\def\fonction#1{\exparg\carre{\number\numexpr3*#1-4\relax}}
+\def\carre#1{\number\numexpr#1*#1\relax}
+a) \fonction{5}\qquad
+b) \fonction{-13}\qquad
+c) \edef\bar{\fonction5}\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 111 ******************
+\def\truncdiv#1#2{\numexpr(#1-(#2-1)/2)/#2\relax}
+8/3 :
+a) \number\truncdiv83\qquad      % doit donner 2
+b) \number\truncdiv{-8}3\qquad   % doit donner -2
+c) \number\truncdiv8{-3}\qquad   % doit donner -2
+d) \number\truncdiv{-8}{-3}\par  % doit donner 2
+4/3 :
+e) \number\truncdiv43\qquad      % doit donner 1
+f) \number\truncdiv{-4}3\qquad   % doit donner -1
+g) \number\truncdiv4{-3}\qquad   % doit donner -1
+h) \number\truncdiv{-4}{-3}      % doit donner 1
+****************** Fin code ******************
+
+
+****************** Code 112 ******************
+a) \ifnum 15=14 vrai\else faux\fi\qquad% test faux
+b) \ifnum4<200 vrai\else faux\fi\qquad% test vrai
+c) \newcount\foo \foo=9
+   \ifnum\foo>9 nombre\else chiffre\fi% test faux
+****************** Fin code ******************
+
+
+****************** Code 113 ******************
+\long\def\>#1<{\detokenize{#1}}
+\expandafter\>\ifnum5=5 vrai\else faux\fi<\par% test vrai
+\expandafter\>\ifnum5=6 vrai\else faux\fi<% test faux
+\fi\fi% r\xE9tablir l'\xE9quilibre \ifnum et \fi
+****************** Fin code ******************
+
+
+****************** Code 114 ******************
+\def\numtest#1{%
+	\ifnum#1>-10 
+		\ifnum#1<10
+			chiffre%
+		\else
+			nombre positif%
+		\fi
+	\else
+		nombre n\xE9gatif%
+	\fi
+}
+a) \numtest{3}\qquad
+b) \numtest{-67}\qquad
+c) \numtest{-8}\qquad
+d) \numtest{21}\qquad
+e) \edef\foo{\numtest{2014}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 115 ******************
+\def\normalise#1{%
+	\ifnum#1>-1 % ne faire quelque chose que si #1 est positif ou nul
+		\ifnum#1<100 % si <100
+			0% afficher un 0
+			\ifnum#1<10 % si <10
+				0%afficher un autre 0
+			\fi
+		\fi
+		\number#1 %afficher le nombre
+	\fi}% affiche le nombre
+a) \normalise{749}\qquad
+b) \normalise{0017}\qquad
+c) \normalise8\qquad
+d) \normalise{1789}\qquad
+e) \normalise{-18}\qquad
+f) \normalise{0}
+****************** Fin code ******************
+
+
+****************** Code 116 ******************
+\def\mois#1{%
+	\ifcase#1\relax
+	    \char`\#\char`\#% afficher "##" si argument = 0
+	\or janvier\or f\'evrier\or mars\or avril%
+	\or mai\or juin\or juillet\or aout%
+	\or septembre\or octobre\or novembre\or d\'ecembre%
+	\else
+	    \char`\#\char`\#% afficher "##" sinon
+	\fi
+}
+a) \mois{-4}\qquad
+b) \mois{3}\qquad
+c) \mois{11}\qquad
+d) \mois{20}\qquad
+e) \edef\foo{\mois{\month}}\meaning\foo% mois en cours
+****************** Fin code ******************
+
+
+****************** Code 117 ******************
+\def\ifletter#1#2#3{%
+	\ifnum`#1<`a% si le caract\xE8re est avant "a"
+		#3% ex\xE9cuter "<code faux>"
+	\else% sinon
+		\ifnum`#1>`z% si le caract\xE8re est apr\xE8s "z"
+			#3% ex\xE9cuter "<code faux>"
+		\else% dans tous les autres cas
+			#2% "#1" est une lettre : ex\xE9cuter "<code vrai>"
+		\fi
+	\fi}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 118 ******************
+\def\ifletter#1{%
+	\ifnum`#1<`a
+		\expandafter\secondoftwo% \expandafter 1-d\xE9veloppe "\else...\fi"
+	\else
+		\ifnum`#1>`z
+			\expandafter\expandafter\expandafter% 1-d\xE9veloppe "\else...\fi" puis "\fi"
+			\secondoftwo
+		\else
+			\expandafter\expandafter\expandafter%1-d\xE9veloppe "\fi" puis "\fi"
+			\firstoftwo
+		\fi
+	\fi}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 119 ******************
+\def\ifletter#1#2#3{%
+	\romannumeral % <- initie le d\xE9veloppement maximal
+	\ifnum`#1<`a
+		\expandafter\secondoftwo
+	\else
+		\ifnum`#1>`z
+			\expandafter\expandafter\expandafter\secondoftwo
+		\else
+			\expandafter\expandafter\expandafter\firstoftwo
+		\fi
+	\fi{0 #2}{0 #3}% <- "0 " stoppe le d\xE9veloppement maximal
+}
+\long\def\>#1<{\detokenize{#1}}
+a) \expandafter\expandafter\expandafter\>\ifletter{0}{vrai}{faux}<\qquad
+b) \expandafter\expandafter\expandafter\>\ifletter{x}{vrai}{faux}<
+****************** Fin code ******************
+
+
+****************** Code 120 ******************
+\def\ifletter#1{%
+	\ifnum`#1<`a
+		\let\donext=\secondoftwo
+	\else
+		\ifnum`#1>`z
+			\let\donext=\secondoftwo
+		\else
+			\let\donext=\firstoftwo
+		\fi
+	\fi
+	\donext% ex\xE9cuter l'action d\xE9cid\xE9e ci-dessus
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 121 ******************
+\def\ifletter#1{%
+	\csname
+		\ifnum`#1<`a
+			second% <- commenter la fin de ligne pour \xE9viter un
+		\else%          espace parasite dans le nom de la macro cr\xE9\xE9e
+			\ifnum`#1>`z
+				second%
+			\else
+				first%
+			\fi
+		\fi
+		oftwo%
+	\endcsname
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 122 ******************
+\def\ifletter#1{%
+	\lowercase{\csname
+		\ifnum`#1<`a second%
+		\else
+			\ifnum`#1>`z second\else first\fi
+		\fi
+	oftwo\endcsname
+	}%
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 123 ******************
+\edef\foo{\lowercase{AbCd}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 124 ******************
+\def\ifletter#1{%
+	\csname
+		\ifnum`#1<`A second%
+		\else
+			\ifnum`#1<`Z first%
+			\else
+				\ifnum`#1>`a
+					\ifnum`#1<`z
+						first%
+					\else
+						second%
+					\fi
+				\else
+					second%
+				\fi
+			\fi
+		\fi
+		oftwo%
+	\endcsname
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}\qquad
+d) \edef\foo{\ifletter{x}{vrai}{faux}}\meaning\foo\qquad
+e) \edef\foo{\ifletter{=}{vrai}{faux}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 125 ******************
+\def\ifinside#1[#2,#3]{%
+	\csname
+		\ifnum#1<#2 second% si n<a, <code faux>
+		\else
+			\ifnum#1>#3 second% si n>b, <code faux>
+			\else       first%  sinon, <code vrai>
+			\fi
+		\fi
+	oftwo%
+	\endcsname
+}
+a) \ifinside 3[1,8]{oui}{non}\qquad
+b) \ifinside -7[-20,-11]{oui}{non}\qquad
+c) \ifinside 9[0,6]{oui}{non}\qquad
+d) \ifinside -1[-5,1]{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 126 ******************
+\def\ifinside#1[#2,#3]{%
+	\ifnum\numexpr(#1-#2)*(#1-#3)\relax>0
+		\expandafter\secondoftwo
+	\else
+		\expandafter\firstoftwo
+	\fi
+}
+a) \ifinside 3[1,8]{oui}{non}\qquad
+b) \ifinside -7[-20,-11]{oui}{non}\qquad
+c) \ifinside 9[0,6]{oui}{non}\qquad
+d) \ifinside -1[-5,1]{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 127 ******************
+\def\absval#1{%
+	\ifnum#1<0 \number-#1
+	\else      \number#1
+	\fi}
+a) \absval{-87}\qquad b) \absval{75}\qquad c) \absval{0}
+****************** Fin code ******************
+
+
+****************** Code 128 ******************
+\def\absval#1{\number\ifnum#1<0 -\fi#1 }
+a) \absval{-87}\qquad b) \absval{75}\qquad c) \absval{0}
+****************** Fin code ******************
+
+
+****************** Code 129 ******************
+\def\absval#1{\number\ifnum\numexpr#1\relax<0 -\fi\numexpr#1\relax}
+a) \absval{-87}\qquad
+b) \absval{75}\qquad
+c) \absval{0}\qquad
+d) \absval{-20+13}\qquad% -7 affich\xE9 7
+e) \absval{5-3*(-4)+10-50}% -23 affich\xE9 23
+****************** Fin code ******************
+
+
+****************** Code 130 ******************
+\catcode`\@11
+\def\absval#1{\exparg\absval at i{\number\numexpr#1\relax}}
+\def\absval at i#1{\number\ifnum#1<\z at -\fi#1 }
+\catcode`\@12
+a) \absval{-87}\qquad
+b) \absval{75}\qquad
+c) \absval{0}\qquad
+d) \absval{-20+13}\qquad% r\xE9sultat -7 qui est affich\xE9 7
+e) \absval{5-3*(-4)+10-50}% r\xE9sultat -23 qui est affich\xE9 23
+****************** Fin code ******************
+
+
+****************** Code 131 ******************
+\def\sgn#1{\ifnum#1<0 -\fi}
+\def\truncdiv#1#2{%
+	\numexpr
+		\sgn{#1}\sgn{#2}1*% multiplie le quotient ci-dessous par +1 ou -1
+		(2*\absval{#1}-\absval{#2}+1)/(2*\absval{#2})
+	\relax
+}
+a) \number\truncdiv{-8}3\qquad
+b) \number\truncdiv{-8}{-3}\qquad
+c) \number\truncdiv8{-3}\qquad
+d) \number\truncdiv{0}{-5}
+****************** Fin code ******************
+
+
+****************** Code 132 ******************
+\catcode`\@11
+\def\sgn#1{\ifnum#1<\z at -\fi}
+\def\truncdiv#1#2{%
+	\exptwoargs\truncdiv at i{\number\numexpr#1\relax}{\number\numexpr#2\relax}%
+}
+\def\truncdiv at i#1#2{%
+	\numexpr(2*\sgn{#1}#1-\sgn{#2}#2+1)/(\sgn{#1}2*#2)\relax
+}
+\catcode`\@12
+a) \number\truncdiv{-8}3\qquad
+b) \number\truncdiv{-8}{-3}\qquad
+c) \number\truncdiv8{-3}\qquad
+d) \number\truncdiv{0}{-5}\qquad
+e) \number\truncdiv{20+2*3}{4-5*2}% 26/(-6) doit donner -4
+****************** Fin code ******************
+
+
+****************** Code 133 ******************
+\def\siecle#1{%
+	\unless\ifnum#1=0 % ne faire quelque chose que si #1 diff\xE9rent de 0
+		\uppercase\expandafter{\romannumeral\absval{#1}}% chiffres romains majuscules
+		\raise 1ex \hbox{e\ifnum\absval{#1}=1 r\fi} si\xE8cle% affiche l'exposant puis "si\xE8cle"
+		\ifnum#1<0 {} av. J.-C.\fi% affiche si besoin "av. J.-C."
+	\fi
+}
+a) \siecle{19}\qquad
+b) \siecle{-3}\qquad
+c) \siecle{1}\qquad
+d) \siecle{0}\qquad
+e) \siecle{-1}
+****************** Fin code ******************
+
+
+****************** Code 134 ******************
+\catcode`\@11
+\edef\saved at catcode{\number\catcode`\:}% sauvegarde du catcode de ":"
+\catcode`\:12 % ":" est d\xE9sormais un caract\xE8re non actif normal
+\def\hdif{%
+	\begingroup% ouvrir un groupe semi-simple
+		\catcode`\:12 % modifier le catcode de ":"
+		\hdif at i% aller lire les deux arguments
+}
+
+\def\hdif at i#1#2{% lit les 2 arguments
+		\hdif at ii#1-#2\@nil% et les transmet \xE0 la macro \xE0 argument d\xE9limit\xE9s
+}
+
+\def\hdif at ii#1:#2:#3-#4:#5:#6\@nil{%
+		%%%%%% calcul des nombres \xE0 afficher %%%%%%
+		\edef\nb at hrs{\number\numexpr#1-#4\relax}% diff\xE9rence des heures
+		\edef\nb at min{\number\numexpr#2-#5\relax}% diff\xE9rence des minutes
+		\edef\nb at sec{\number\numexpr#3-#6\relax}% diff\xE9rence des secondes
+		\ifnum\nb at sec<\z@ % si la diff\xE9rence des secondes est <0
+			\edef\nb at sec{\number\numexpr\nb at sec+60\relax}% ajouter 60 sec
+			\edef\nb at min{\number\numexpr\nb at min-1\relax}% enlever 1 aux minutes
+		\fi
+		\ifnum\nb at min<\z@ % si les minutes sont <0
+			\edef\nb at min{\number\numexpr\nb at min+60\relax}% ajouter 60 min
+			\edef\nb at hrs{\number\numexpr\nb at hrs-1\relax}% enlever 1 aux heures
+		\fi
+		%%%%%% affichage du r\xE9sultat %%%%%%
+		\let\inter at space\empty% pas d'espace avant un nombre pour l'instant
+		\ifnum\nb at hrs>\z@ % si les heures sont >0
+			\nb at hrs h% afficher les heures et "h"
+			\let\inter at space\space% espace pour plus tard
+		\fi
+		\ifnum\nb at min>\z@ % si les minutes sont >0
+			\inter at space% afficher une espace \xE9ventuelle
+			\nb at min min% afficher les minutes et "min"
+			\let\inter at space\space
+		\fi
+		\ifnum\nb at sec>\z@ % si les secondes sont >0
+			\inter at space% afficher une espace \xE9ventuelle
+			\nb at sec s% afficher les secondes et "s"
+		\fi
+	\endgroup% fermer le groupe ouvert au d\xE9but
+}
+\catcode`\:=\saved at catcode\relax% restaure le code de cat\xE9gorie de ":"
+\catcode`\@12
+a) \hdif{10:51:20}{9:20:10}\par
+b) \hdif{14:20:0}{13:50:0}\par
+c) \hdif{7:50:20}{5:50:20}\par
+d) \hdif{7:50:10}{6:50:20}\par
+e) \hdif{20:00:00}{19:59:15}\par
+f) \hdif{17:13:15}{14:12:45}
+****************** Fin code ******************
+
+
+****************** Code 135 ******************
+\newcount\ii
+\catcode`\@=11
+\def\ncar#1#2{%
+    \ii=0 % initialise le compteur \xE0 0
+    \def\val at max{#1}% stocke la valeur maximale
+    \def\car at save{#2}% stocke le caract\xE8re \xE0 afficher
+    \ncar at i% appelle la macro r\xE9cursive
+}
+\def\ncar at i{%
+  \ifnum\ii<\val at max% si la valeur maxi n'est pas atteinte
+    \car at save% afficher le caract\xE8re
+    \advance\ii 1 % incr\xE9menter le compteur
+    \ncar at i% recommencer
+  \fi
+}
+\catcode`\@=12
+\ncar{7}{*}\par
+\ncar{13}W\par
+\ncar{10}{foobar }
+****************** Fin code ******************
+
+
+****************** Code 136 ******************
+\newcount\ii
+\catcode`\@=11
+\def\ncar#1#2{%
+    \ii=0 % initialise le compteur \xE0 0
+    \def\val at max{#1}% stocke la valeur maximale
+    \def\car at save{#2}% stocke le caract\xE8re \xE0 afficher
+    \ncar at i% appelle la macro r\xE9cursive
+}
+\def\ncar at i{%
+  \ifnum\ii<\val at max% si la valeur maxi n'est pas atteinte
+    \car at save% afficher le caract\xE8re
+    \advance\ii 1 % incr\xE9menter le compteur
+    \ncar at i% recommencer
+  \fi
+}
+\catcode`\@=12
+\ncar{2}{3a}
+****************** Fin code ******************
+
+
+****************** Code 137 ******************
+a) \romannumeral 9600 \qquad b) \romannumeral 12000
+****************** Fin code ******************
+
+
+****************** Code 138 ******************
+\def\ncar#1#2{%
+	\begingroup
+	\lccode`\m=`#2 % dans \lowercase, les "m" deviennent des "#2"
+	\lowercase\expandafter{\expandafter\endgroup\romannumeral#1000 }%
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{15}{\%}\qquad
+c) \ncar{10}{4}
+****************** Fin code ******************
+
+
+****************** Code 139 ******************
+\def\ncar#1#2{%
+  \ifnum#1>0 % <- espace apr\xE8s le "0"
+    #2% affiche le caract\xE8re
+    \exparg\ncar{\number\numexpr#1-1}{#2}% appel r\xE9cursif
+  \fi
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}{7}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 140 ******************
+\def\ncar#1#2{%
+	\ifnum#1>0 \expandafter\identity% si #1>0 ex\xE9cuter...
+	\else      \expandafter\gobone% ...sinon manger
+	\fi% ce qui est entre ces accolades :
+		{#2% afficher le caract\xE8re
+		\exparg\ncar{\number\numexpr#1-1}{#2}% appel r\xE9cursif
+		}%
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 141 ******************
+\long\def\antefi#1\fi{\fi#1}
+\def\ncar#1#2{%
+	\ifnum#1>0
+		\antefi% comme si le \fi \xE9tait "d\xE9plac\xE9" ici
+		#2% affiche le caract\xE8re
+		\exparg\ncar{\number\numexpr#1-1}{#2}% appel r\xE9cursif
+	\fi
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 142 ******************
+\long\def\afterfi#1#2\fi{#2\fi#1}
+\def\ncar#1#2{%
+	\ifnum#1>0
+		\afterfi{\exparg\ncar{\number\numexpr#1-1}{#2}}% <- argument renvoy\xE9 apr\xE8s le \fi
+		#2% <- ceci reste avant le \fi
+	\fi
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 143 ******************
+\def\ncar#1#2{%
+  \ifnum#1>0
+    #2% afficher le caract\xE8re
+    \expandafter\ncar\expandafter% le pont d'\expandafter lance \number et \numexpr
+		{\number\numexpr#1-1\expandafter}% le dernier \expandafter mange "\else...\fi"
+  \else
+    \expandafter\gobone% si le test est faux, manger {#2} ci-dessous
+  \fi{#2}%
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 144 ******************
+\catcode`\@11
+\def\ncar#1#2{%
+	\def\ncar at i##1{%
+		\ifnum##1<#1 % si i < valeur maxi
+		#2% afficher le caract\xE8re
+		\exparg\ncar at i{\number\numexpr##1+1\expandafter}% puis recommencer avec i+1
+		\fi% \fi mang\xE9 par le \expandafter en fin de zone de \numexpr
+	}%
+	\ncar at i{0}% commence avec la valeur "compteur" 0
+}
+\catcode`\@12
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \ncar{5}{X}
+****************** Fin code ******************
+
+
+****************** Code 145 ******************
+\catcode`\@11 \newcount\compte at cnt
+\def\compte#1{%
+	\def\val at max{#1}\compte at cnt=0 % effectue les initialisations
+	\compte at i% appelle la macro principale
+}
+\def\compte at i{%
+	\ifnum\compte at cnt<\val at max% si compteur < valeur maxi
+		\advance\compte at cnt1 % incr\xE9menter le compteur
+		\number\compte at cnt, % afficher le nombre, la virgule et l'espace
+		\expandafter\compte at i %recommencer
+	\fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \compte{2}
+****************** Fin code ******************
+
+
+****************** Code 146 ******************
+\catcode`\@11 \newcount\compte at cnt
+\def\compte#1{\def\val at max{#1}\compte at cnt=0 \compte at i}
+\def\compte at i{%
+	\ifnum\compte at cnt<\val at max\relax
+		\advance\compte at cnt1 
+		\number\compte at cnt
+		\ifnum\compte at cnt<\val at max , \fi% afficher ", " si le maxi n'est pas atteint
+		\expandafter\compte at i
+	\fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b)\compte{-4}\qquad
+c) \compte{2}
+****************** Fin code ******************
+
+
+****************** Code 147 ******************
+\catcode`\@11 \newcount\compte at cnt
+\def\compte#1{%
+  \ifnum#1>0 % ne faire quelque chose que si l'argument est positif
+    \def\val at max{#1}\compte at cnt=1 % faire les initialisations
+    \expandafter\compte at i% appeller la macro r\xE9crusive
+  \fi
+}
+\def\compte at i{%
+  \number\compte at cnt\relax % afficher le nombre
+  \ifnum\compte at cnt<\val at max\relax % si valeur maxi n'est pas atteinte
+    , % afficher la virgule et l'espace
+    \advance\compte at cnt1 % incr\xE9menter le compteur
+    \expandafter\compte at i % recommencer
+  \fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \compte{2}
+****************** Fin code ******************
+
+
+****************** Code 148 ******************
+\catcode`\@11
+\def\compte#1{%
+	\ifnum#1>\z@% ne faire quelque chose que si #1 > 0
+		\antefi\compte at i{1}{#1}%
+	\fi
+}
+
+\def\compte at i#1#2{%
+	#1% afficher le nombre
+	\ifnum#1<#2 % si le maxi n'est pas atteint
+		\expandafter\identity% ex\xE9cuter...
+	\else
+		\expandafter\gobone% sinon, manger...
+	\fi% le code entre accolades ci-dessous
+		{, % afficher la virgule et l'espace
+		\exparg\compte at i{\number\numexpr#1+1}{#2}% appel r\xE9cursif
+		}%
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \edef\foo{\compte{2}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 149 ******************
+\catcode`\@11
+\def\compte#1{%
+	\ifnum#1>\z@% ne faire quelque chose que si #1 > 0
+		\antefi\compte at i{1}{#1}%
+	\fi
+}
+
+\def\compte at i#1#2{%
+  #1% afficher le nombre
+  \ifnum#1<#2 % si le maxi n'est pas atteint
+    \antefi% d\xE9place le \fi ici
+    , % affiche la virgule et l'espace
+    \exparg\compte at i{\number\numexpr#1+1}{#2}% appel r\xE9cursif
+  \fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \edef\foo{\compte{2}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 150 ******************
+\catcode`\@11
+\def\for#1=#2to#3\do#4{% #1=\<macro>   #2=n1   #3=n2   #4=<code>
+	\def#1{#2}% initialise la \<macro> \xE0 l'entier n1
+	\def\val at max{#3}% stocke n2
+	\def\loop at code{#4}% stocke le <code>
+	\for at i#1% appelle la macro r\xE9cursive et passe la \<macro> en argument
+}
+\def\for at i#1{%
+	\unless\ifnum#1>\val at max\relax% tant que la \<macro> est <= n2
+		\loop at code% effectue le code pr\xE9c\xE9demment sauvegard\xE9
+		\edef#1{\number\numexpr#1+1}% incr\xE9menter la \<macro>
+		\expandafter\for at i\expandafter#1% et recommencer apr\xE8s avoir mang\xE9 le \fi
+	\fi
+}
+\catcode`\@=12
+\for\ii=1to5\do{Maintenant \string\ii\ vaut : \ii.\endgraf}\medbreak
+"\for\ii=1to0\do{A}"\medbreak% boucle parcourue 0 fois
+"\for\ii=1to1\do{A}"\medbreak% boucle parcourue 1 fois
+\for\ii = 0 to 10 \do {[\ii]}.
+****************** Fin code ******************
+
+
+****************** Code 151 ******************
+\catcode`\@11
+\long\def\for#1=#2to#3\do#4{%
+	\def\for at i{%
+		\unless\ifnum#1>\val at max\relax% tant que la \<macro> <= n2
+			#4% code \xE0 ex\xE9cuter
+			\edef#1{\number\numexpr#1+1}% incr\xE9menter \<macro>
+			\expandafter\for at i% et recommencer apr\xE8s avoir mang\xE9 le \fi
+		\fi
+	}%
+	\edef#1{\number\numexpr#2\relax}% initialise la variable \xE0 n1
+	\edef\val at max{\number\numexpr#3\relax}% stocke n2
+	\for at i% appelle la sous-macro r\xE9cursive
+}
+\catcode`\@=12
+\for\ii = 1 to 5 \do {Maintenant \string\ii\ vaut : \ii.\par}\medbreak
+"\for\ii=1to0\do{A}"\medbreak% boucle parcourue 0 fois
+"\for\ii=1to1\do{A}"\medbreak% boucle parcourue 1 fois
+\for\ii = 0 to 10 \do {[\ii]}.
+****************** Fin code ******************
+
+
+****************** Code 152 ******************
+\catcode`\@11
+\def\for#1=#2to#3\do#4#{%
+	\edef\for at increment{\number\numexpr0#4}% lit et normalise l'argument optionnel
+	\ifnum\for at increment=\z@% s'il est nul,
+		\edef\for at increment{% le red\xE9finir :
+			\ifnum\numexpr#3\relax<\numexpr#2\relax
+				-% ajoute un signe - si #3<#2
+			\fi
+			1% devant "1"
+		}% \for at increment vaut donc 1 ou -1
+	\fi
+	\ifnum\numexpr\for at increment*(#3-#2)\relax<\z@% si l'argument est incompatible
+		\expandafter\firstoftwo% ex\xE9cuter le 1er argument qui suit
+	\else
+		\expandafter\secondoftwo% sinon le second
+	\fi
+		{Incr\xE9ment incompatible !\gobone %\gobone mangera le <code> qui \xE0 lire
+		}%
+		{\edef#1{\number\numexpr#2\relax}% initialise la \<macro>
+		\edef\cmp at sgn{\ifnum\for at increment<\z@<\else>\fi}% stocke "<" ou ">" pour plus tard
+		\expandafter\for at i\expandafter#1\expandafter% appelle la macro r\xE9cursive
+			{\number\numexpr#3\relax}% et lui lui passe la \<macro> (#1) et n2 (#3)
+		}%
+}
+
+% #1 = \<macro>   #2 = n2
+\long\def\for at i#1#2#3{% l'argument #3 (le <code>) est lu \xE0 ce moment-l\xE0
+	\def\for at ii{%
+		\unless\ifnum#1\cmp at sgn#2\relax% tant que la \<macro> n'a pas d\xE9pass\xE9 n2
+			#3% ex\xE9cute le <code>
+			\edef#1{\number\numexpr#1+\for at increment}% incr\xE9mente la \<macro>
+			\expandafter\for at ii% recommence apr\xE8s avoir mang\xE9 le \fi
+		\fi
+	}%
+	\for at ii% appelle la sous-macro r\xE9cursive
+}%
+\catcode`\@=12
+a) \for\ii = -4 to 7 \do{(\ii)}\par
+b) \for\jj = 20 to -50\do-10 {(\jj)}\par
+c) \for\xx = 8 to 185\do 20 {[\xx]}\par
+d) \for\yy = 0 to 10\do -2{(\yy)}\par
+e) "\for\ii = 1 to 0 \do1{XX}"\par
+f) "\for\ii = 1 to 1 \do{A}"\par% boucle parcourue 1 fois
+g) \for\ii=1to4\do{\for\jj=0to2\do{(\ii,\jj)}\par}% imbrication de boucles
+****************** Fin code ******************
+
+
+****************** Code 153 ******************
+\catcode`\@11
+\def\for#1=#2to#3\do#4#{%
+	\edef\for at increment{\number\numexpr0#4}% lit et normalise l'argument optionnel
+	\ifnum\for at increment=\z@% s'il est nul,
+		\edef\for at increment{% le red\xE9finir \xE0 -1 (si #3<#2) et 1 sinon
+			\ifnum\numexpr#3-#2\relax<\z@ -1\else 1\fi
+		}% \for at increment vaut donc 1 ou -1
+	\fi
+	\ifnum\numexpr\for at increment*(#3-#2)\relax<\z@
+		\expandafter\gobone% si argument optionnel incompatible, manger le {<code>}
+	\else
+		\edef#1{\number\numexpr#2}% initialise la \<macro>
+		\edef\macro at args{% d\xE9finit et d\xE9veloppe les arguments \xE0 passer \xE0 \for at i
+			%#1=nom de la macro r\xE9cursive :
+			\expandafter\noexpand\csname for at ii@\string#1\endcsname
+			\ifnum\for at increment<\z@ <\else >\fi% #2=signe de comparaison
+			{\for at increment}% #3=incr\xE9ment
+			\noexpand#1% #4=\<macro>
+			{\number\numexpr#3\relax}% #5=entier n2
+		}%
+		\antefi% externalise la ligne ci-dessous de la port\xE9e du test
+		\expandafter\for at i\macro at args% appelle \for at i avec les arguments d\xE9finis ci-dessus
+	\fi
+}
+
+% #1=nom de la macro r\xE9cursive de type "\for at ii@\<macro>"
+% #2=signe de comparaison  % #3=incr\xE9ment
+% #4=\<macro>  % #5=entier n2  % #6=<code> \xE0 ex\xE9cuter
+\long\def\for at i#1#2#3#4#5#6{%
+	\def#1{% d\xE9finit la sous macro r\xE9cursive
+		\unless\ifnum#4#2#5\relax% tant que la \<macro> variable n'a pas d\xE9pass\xE9 n2
+			\afterfi{% rendre la r\xE9cursivit\xE9 terminale
+				#6% ex\xE9cute le code
+				\edef#4{\number\numexpr#4+#3\relax}% incr\xE9mente la \<macro>
+				#1% recommence
+			}%
+		\fi
+	}%
+	#1% appelle la sous-macro r\xE9cursive
+}%
+\catcode`\@=12
+\for\ii=1to4\do{\for\jj=0to2\do{(\ii,\jj)}\par}\medbreak
+
+\for\carA= `\A to `\E \do{\for\carB= `w to `z \do{\char\carA\char\carB}\quad}
+****************** Fin code ******************
+
+
+****************** Code 154 ******************
+\catcode`\@11
+\long\def\for at i#1#2#3#4#5#6{%
+	\def\exitfor{\def#1{}}%
+	\def#1{% d\xE9finit la sous macro r\xE9cursive
+		\unless\ifnum#4#2#5\relax% tant que la variable n'a pas d\xE9pass\xE9 l'entier max
+			\afterfi{% rendre la r\xE9cursivit\xE9 terminale
+				#6% ex\xE9cute le code
+				\edef#4{\number\numexpr#4+#3\relax}% incr\xE9mente la variable #1
+				#1% recommence
+			}%
+		\fi
+	}%
+	#1% appelle la sous-macro r\xE9cursive
+}%
+\catcode`\@=12
+\for\ii= 1 to 9 \do{\string\ii{} vaut \ii.\ifnum\ii=5 \exitfor\fi\par}
+****************** Fin code ******************
+
+
+****************** Code 155 ******************
+\def\exitfor#1{% #1=\<macro> correspondant \xE0 la boucle de laquelle on veut sortir
+	\defname{for at ii@\string#1}{}
+}
+
+\def\ifexitfor#1{% envoie vrai si on est pr\xE9matur\xE9ment sorti de la boucle de \<macro> #1
+	% si la macro r\xE9cursive est \xE9gale \xE0 la macro "\empty"
+	\expandafter\ifx\csname for at ii@\string#1\endcsname\empty
+		\expandafter\firstoftwo% c'est qu'on est sortir pr\xE9matur\xE9ment, renvoyer "vrai"
+	\else
+		\expandafter\secondoftwo% sinon, renvoyer "faux"
+	\fi
+}
+
+% on ne sort QUE de la boucle int\xE9rieure quand \ii=3 donc
+% les boucles sont normalement ex\xE9cut\xE9es pour \ii=4 et \ii=5
+a. \for\ii=1 to 5\do1{%
+     \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\jj\fi}%
+     \qquad
+   }
+
+% on sort de la boucle ext\xE9rieure lorsque \ii=3 donc la boucle
+% int\xE9rieure est faite enti\xE8rement m\xEAme lorsque \ii=3
+b. \for\ii=1 to 5\do1{%
+     \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\ii\fi}%
+     \qquad
+   }
+
+% on sort de la boucle int\xE9rieure lorsque \ii=3
+% et aussi de la boucle ext\xE9rieure \xE0 l'aide de \ifexitfor
+c. \for\ii=1 to 5\do1{%
+     \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\jj\fi}%
+     \ifexitfor\jj{\exitfor\ii}{}% si on est sorti de \jj, sortir aussi de \ii
+     \qquad
+   }
+****************** Fin code ******************
+
+
+****************** Code 156 ******************
+\def\foo{a}\ifx a\foo vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 157 ******************
+1) \meaning9\par% un caract\xE8re de catcode 12
+2) \meaning a\par% une lettre
+3) \def\foo{a}\meaning\foo\par% une macro
+4) \long\def\foo{a}\meaning\foo\par% une macro d\xE9clar\xE9e \long
+5) \meaning\sdlkfj\par% une macro ind\xE9finie
+6) \edef\foo{\string a}\meaning\foo\par%\foo contient un "a" de catcode 12
+7) \def\foo{a}\meaning\foo\par%\foo contient un "a" de catcode 11
+****************** Fin code ******************
+
+
+****************** Code 158 ******************
+a) \ifx abvrai\else faux\fi\quad% a est n'est pas \xE9gal \xE0 b
+b) \ifx++vrai\else faux\fi\quad% le caract\xE8re "+" est \xE9gal \xE0 "+"
+c) \ifx\relax\par vrai\else faux\fi\quad% \relax n'est pas la m\xEAme primitive que \par
+d) \ifx\par\par vrai\else faux\fi\quad% \par et \par sont les m\xEAmes primitives
+e) \ifx\sdfk\qlms vrai\else faux\fi\quad% 2 macros non d\xE9finies sont \xE9gales
+f) \def\foo{abcd}\def\bar{abc}% \foo et \bar ont des textes de remplacement diff\xE9rents
+   \ifx\foo\bar vrai\else faux\fi\quad
+g) \def\foo{abcd}\def\bar{abcd }% \foo et \bar ont des textes de remplacement diff\xE9rents
+   \ifx\foo\bar vrai\else faux\fi\quad
+h) \def\foo{abcd}\def\bar{abcd}
+   \ifx\foo\bar vrai\else faux\fi\quad% \foo et \bar ont les m\xEAmes textes de remplacement
+i) \long\def\foo{a}\def\bar{a}
+   \ifx\foo\bar vrai\else faux\fi\quad% \foo est \long, \bar ne l'est pas
+j) \edef\foo{\string a}% \foo contient un "a" de catcode 12
+   \def\bar{a}% \bar contient un "a" de catcode 11
+   \ifx\foo\bar vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 159 ******************
+\def\cmpmacro#1#2{%
+	\begingroup
+	\edef\tempa{\detokenize\expandafter{#1}}\edef\tempb{\detokenize\expandafter{#2}}%
+	\ifx\tempa\tempb% si \xE9galit\xE9
+		\endgroup\expandafter\firstoftwo% ferme le groupe et lit 1er argument
+	\else
+		\endgroup\expandafter\secondoftwo% sinon, ferme le groupe et lit le 2e argument
+	\fi
+}
+a) \edef\foo{\string a}\def\bar{a}
+   \cmpmacro\foo\bar{vrai}{faux}\qquad
+b) \edef\foo{\detokenize{$i^2=-1$\relax}}\def\bar{$i^2=-1$\relax}
+   \cmpmacro\foo\bar{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 160 ******************
+a) \let\rien\relax      \ifx\rien\relax vrai\else faux\fi\qquad
+b) \let\AA=a            \ifx a\AA vrai\else faux\fi\qquad
+c) \let\foo=_\let\bar=_ \ifx\foo\bar vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 161 ******************
+\def\quark{\quark}% d\xE9finit un quark
+1) \def\test{\quark} \ifx\quark\test vrai\else faux\fi
+\qquad
+2) \let\test=\quark  \ifx\quark\test vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 162 ******************
+\def\ifempty#1{%
+	\def\tempa{#1}% stocke l'argument #1 dans \tempa
+	\ifx\tempa\empty% si \tempa = \empty
+		\expandafter\firstoftwo% 1er argument
+	\else
+		\expandafter\secondoftwo% sinon, second
+	\fi
+}
+a) \ifempty{abc}{vide}{pas vide}\qquad
+b) \ifempty{}{vide}{pas vide}\qquad
+c) \ifempty{ }{vide}{pas vide}\qquad
+d) \ifempty{\empty}{vide}{pas vide}
+****************** Fin code ******************
+
+
+****************** Code 163 ******************
+\def\empty{}
+\long\def\ifempty#1{%
+  \ifx_#1_\expandafter\firstoftwo
+  \else\expandafter\secondoftwo
+  \fi}
+a) \ifempty{abc}{vide}{pas vide}\qquad
+b) \ifempty{}{vide}{pas vide}\qquad
+c) \ifempty{ }{vide}{pas vide}\qquad
+d) \ifempty{\empty}{vide}{pas vide}\qquad
+e) \edef\foo{\ifempty{abc}{vide}{pas vide}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 164 ******************
+\long\def\ifempty#1{%
+  \ifx W#1W\expandafter\firstoftwo
+  \else    \expandafter\secondoftwo
+  \fi}
+1) \ifempty{foobar}{vide}{pas vide}\qquad
+2) \ifempty{}{vide}{pas vide}\qquad
+2) \ifempty{\empty}{vide}{pas vide}\qquad
+4) \ifempty{Wagons}{vide}{pas vide}
+****************** Fin code ******************
+
+
+****************** Code 165 ******************
+\long\def\ifempty#1{%
+	\expandafter\ifx\expandafter\relax\detokenize{#1}\relax
+		\expandafter\firstoftwo
+	\else
+		\expandafter\secondoftwo
+	\fi
+}
+a) \ifempty{abc}{vide}{pas vide}\qquad
+b) \ifempty{}{vide}{pas vide}\qquad
+c) \ifempty{ }{vide}{pas vide}\qquad
+d) \ifempty{\relax}{vide}{pas vide}\qquad
+e) \edef\foo{\ifempty{abc}{vide}{pas vide}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 166 ******************
+\catcode`\@11
+\def\reverse#1{%
+	\ifempty{#1}
+		{}% s'il n'y a rien \xE0 inverse, ne rien faire
+		{\reverse at i#1\@nil\@nil}% initialisation des r\xE9servoirs et appeler \reverse at i
+}
+\def\reverse at i#1#2\@nil#3\@nil{% #1 est le 1er caract\xE8re du r\xE9servoir A
+	\ifempty{#2}% si ce qui reste apr\xE8s ce 1er caract\xE8re est vide
+		{#1#3}% renvoyer #1#3 qui est le r\xE9sultat final
+		{\reverse at i#2\@nil#1#3\@nil}% sinon, recommencer en d\xE9pla\xE7ant #1
+		                            % en 1re position du r\xE9servoir B
+}
+\catcode`\@12
+a) \reverse{foobar}\qquad
+b) \edef\foo{\reverse{Bonjour}}\meaning\foo\qquad
+c) \reverse{Bonjour le monde}\qquad
+d) \reverse{Bonjour{ }le{ }monde}
+****************** Fin code ******************
+
+
+****************** Code 167 ******************
+\catcode`\@11
+\def\ifin#1#2{%
+	\def\ifin at i##1#2##2\@nil{% d\xE9finit la macro auxiliaire
+		\ifempty{##2}% si ce qu'il y a derri\xE8re le motif est vide
+			\secondoftwo% aller \xE0 "faux"
+			\firstoftwo% sinon \xE0 "vrai"
+	}%
+	\ifin at i#1#2\@nil% appel de la macro auxiliaire
+}
+\catcode`\@12
+a) \ifin{abc\relax1}{bc}{vrai}{faux}\qquad
+b) \ifin{abc \relax1}{c\relax}{vrai}{faux}\qquad
+c) \ifin{abc \relax1}{ }{vrai}{faux}\qquad
+d) \ifin{abc \relax1}{}{vrai}{faux}\qquad
+e) \ifin{}{a}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 168 ******************
+\catcode`\@11
+\def\ifstart#1#2{%
+	\def\ifstart at i##1#2##2\@nil{\ifempty{##1}}%
+	\ifstart at i#1#2\@nil
+}
+\catcode`\@12
+a) \ifstart{abc}{bc}{vrai}{faux}\qquad
+b) \ifstart{abc}{ab}{vrai}{faux}\qquad
+c) \ifstart{ abc}{ }{vrai}{faux}\qquad
+d) \ifstart{abc}{}{vrai}{faux}\qquad
+e) \ifstart{}{a}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 169 ******************
+\catcode`\@11
+\def\ifstart#1#2{%
+	\def\ifstart at i##1#2##2\@nil{\ifempty{##1}}%
+	\ifempty{#2}% si motif vide
+		\firstoftwo% ex\xE9cuter code "vrai"
+		{\ifstart at i#1\relax#2\@nil}% sinon, aller \xE0 la macro auxiliaire
+}
+\catcode`\@12
+a) \ifstart{abc}{bc}{vrai}{faux}\qquad
+b) \ifstart{abc}{ab}{vrai}{faux}\qquad
+c) \ifstart{ abc}{ }{vrai}{faux}\qquad
+d) \ifstart{abc}{}{vrai}{faux}\qquad
+e) \ifstart{}{a}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 170 ******************
+\catcode`\@11
+\def\ifend#1#2{%
+	\def\ifend at i##1#2##2\@nil{% ##2 = ce qui reste apr\xE8s le motif
+		\ifempty{##2}% si ##2 est vide
+			\firstoftwo% ex\xE9cuter l'argument "vrai"
+			{\ifin{##2}{#2}% sinon, si ##2 contient le <motif>
+				{\ifend at i##2\@nil}% appeler \ifend at i avec ce qui reste
+				\secondoftwo% sinon, ex\xE9cuter l'argument "faux"
+			}%
+	}%
+	\ifend at i#2#1\@nil% appelle la macro r\xE9cursive
+}
+\catcode`\@12
+1) \ifend{abc de}{de}{vrai}{faux}\qquad
+2) \ifend{abd de }{de}{vrai}{faux}\qquad
+3) \ifend{abc de }{ }{vrai}{faux}\qquad
+4) \ifend{}{a}{vrai}{faux}\qquad
+5) \ifend{abc de}{}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 171 ******************
+\catcode`\@11
+\def\ifend#1#2{%
+	\def\ifend at i##1#2##2\@nil{% ##2 = ce qui reste apr\xE8s le motif
+		\ifempty{##2}% si ##2 est vide
+			\firstoftwo% ex\xE9cuter l'argument "vrai"
+			{\ifin{##2}{#2}% sinon, si ##2 contient le <motif>
+				{\ifend at i##2\@nil}% appeler \ifend at i avec ce qui reste
+				\secondoftwo% sinon, ex\xE9cuter l'argument "faux"
+			}%
+	}%
+	\ifempty{#2}% si le motif est vide
+		\firstoftwo% ex\xE9cuter "vrai"
+		{\ifend at i#2\relax#1\@nil}% sinon, appelle la macro r\xE9cursive
+}
+\catcode`\@12
+1) \ifend{abc de}{de}{vrai}{faux}\qquad
+2) \ifend{abd de }{de}{vrai}{faux}\qquad
+3) \ifend{abc de }{ }{vrai}{faux}\qquad
+4) \ifend{}{a}{vrai}{faux}\qquad
+5) \ifend{abc de}{}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 172 ******************
+\catcode`\@11
+\def\substin#1#2#3{%
+	\def\substin at i##1{%
+		\ifempty{##1}% si le <code> est vide
+			\relax% ne rien faire -> fin du processus
+			{\ifin{##1}{#2}% sinon, si le <code> contient <motif1>
+				{\substin at ii##1\@nil}% appeler la macro \xE0 argument d\xE9limit\xE9s
+				{##1}% sinon, afficher le <code>
+			}%
+	}%
+	\def\substin at ii##1#2##2\@nil{%
+		##1#3% afficher ##1 et #3 (qui est <motif2>)
+		\substin at i{##2}% et recommencer avec ce qui reste
+	}%
+	\substin at i{#1}%
+}
+\catcode`\@12
+a) \substin{abracadabra}{a}{A}\qquad
+b) \substin{abracadabra}{x}{W}\qquad
+c) \substin{abracadabra}{br}{}\qquad
+d) \substin{1\relax3}\relax{222}\qquad
+****************** Fin code ******************
+
+
+****************** Code 173 ******************
+\catcode`\@11
+\def\substtocs#1#2#3#4{%
+	\def\substtocs at i##1{%
+		\ifempty{##1}% si le <code> est vide
+			\relax% ne rien faire -> fin du processus
+			{\ifin{##1}{#3}% sinon, si le <code> contient <motif1>
+				{\substtocs at ii##1\@nil}% appeler la macro \xE0 argument d\xE9limit\xE9s
+				{\addtomacro#1{##1}}% sinon, ajouter le <code>
+			}%
+	}%
+	\def\substtocs at ii##1#3##2\@nil{%
+		\addtomacro#1{##1#4}% ajouter ##1#4
+		\substtocs at i{##2}% et recommencer avec ce qui reste
+	}%
+	\let#1=\empty% initialise la macro \xE0 vide
+	\substtocs at i{#2}%
+}
+\catcode`\@12
+\substtocs\foo{abracadabra}{a}{A}\meaning\foo\par
+\substtocs\foo{abracadabra}{x}{W}\meaning\foo\par
+\substtocs\foo{abracadabra}{br}{}\meaning\foo\par
+\substtocs\foo{1\relax3}\relax{222}\meaning\foo\par
+\substtocs\foo{\ifnum1=2 test vrai\fi}{2}{1}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 174 ******************
+\def\majuscule#1{\uppercase{#1}}
+\def\majmot#1{\substin{\majuscule#1}{ }{ \majuscule}}
+\majmot{un petit texte}\par
+\majmot{Un grand texte sans importance}
+****************** Fin code ******************
+
+
+****************** Code 175 ******************
+\def\majuscule#1{\uppercase{#1}}
+\def\majmot#1{%
+	\begingroup
+		\substtocs\temp{\majuscule#1}{ }{ \majuscule}%
+		\temp% ex\xE9cute la macro temporaire
+	\endgroup
+}
+\majmot{un petit texte}\par
+\majmot{Un grand texte Sans importance}
+****************** Fin code ******************
+
+
+****************** Code 176 ******************
+\catcode`\@11
+\newcount\cnt at occ
+\def\cnttimes#1#2{%
+	\def\cnttimes at i##1{%
+		\ifempty{##1}% si le <code> est vide
+			{\number\cnt at occ}% afficher le nombre d'occurrences
+			{\ifin{##1}{#2}% sinon, si le <code> contient <motif1>
+				{\cnttimes at ii##1\@nil}% appeler la macro \xE0 argument d\xE9limit\xE9s
+				{\number\cnt at occ}% sinon, afficher le nombre d'occurrences
+			}%
+	}%
+	\def\cnttimes at ii##1#2##2\@nil{%
+		\advance\cnt at occ1
+		\cnttimes at i{##2}% et recommencer avec ce qui reste
+	}%
+	\cnt at occ=0 % initialise le compteur
+	\cnttimes at i{#1}%
+}
+\catcode`\@12
+a) \cnttimes{abracadabra}{a}\qquad
+b) \cnttimes{abracadabra}{ra}\qquad
+c) \cnttimes{abracadabra}{w}\qquad
+d) \cnttimes{abc def ghijk l }{ }\qquad
+e) \cnttimes{\ifnum1=2 vrai\else faux\fi}{\ifnum}
+****************** Fin code ******************
+
+
+****************** Code 177 ******************
+\catcode`\@11
+\long\def\cnttimestocs#1#2#3{% #3=macro recevant le r\xE9sultat
+	\long\def\cnttimestocs at i##1\@nil##2#2##3\@nil{%
+		% ##1=nb d'occurrences rencontr\xE9es jusqu'alors
+		% ##2 et ##3=ce qui est avant/apr\xE8s le <motif>
+		\ifin{##3}{#2}% si le <motif> est dans ce qui reste
+			{\expandafter\cnttimestocs at i% appeler la macro r\xE9cursive
+				\number\numexpr##1+1\relax\@nil% avec une occurrence de plus
+				##3\@nil% et ce qui reste
+			}%
+			{\edef#3{\number\numexpr##1+1\relax}}% sinon, stocker 1 occurrence de plus dans #3
+	}%
+	\ifin{#1}{#2}% si le <motif> est dans le <code>
+		{\cnttimestocs at i 0\@nil#1\@nil}% appeler la macro r\xE9cursive avec 0 occurrence
+		{\def#3{0}}% sinon, mettre 0 dans #3
+}
+\catcode`\@12
+a) \cnttimestocs{abracadabra}{a}\foo \meaning\foo\qquad
+b) \cnttimestocs{abracadabra}{ra}\foo \meaning\foo\qquad
+c) \cnttimestocs{abracadabra}{w}\foo \meaning\foo\qquad
+d) \cnttimestocs{abc def ghijk l }{ }\foo \meaning\foo\qquad
+e) \cnttimestocs{\ifnum1=2 vrai\else faux\fi}{\ifnum}\foo \meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 178 ******************
+\catcode`\@11
+\def\multisubst#1#2{%
+	\def\subst at code{#1}% stocke le <code>
+	\multisubst at i#2\@nil% appelle la macro r\xE9cursive avec la liste de motifs
+}
+
+\def\multisubst at i#1#2#3\@nil{% #1 et #2=paire de motifs  #3=motifs restants
+	\expandafter\substtocs\expandafter\subst at code\expandafter% 1-d\xE9veloppe
+		{\subst at code}{#1}{#2}% le <code> et effectue la substitution en cours
+	\ifempty{#3}% si la liste des motifs est vide
+		\subst at code% ex\xE9cuter le <code> obtenu
+		{\multisubst at i#3\@nil}% recommencer avec les motifs qui restent
+}
+\catcode`\@12
+1) \multisubst{abracadabra}{aA rR}\par
+2) \multisubst{Ce texte devenu \`a peine reconnaissable montre que le
+   r\'esultat contient des sonorit\'es catalanes, corses ou grecques
+   assez inattendues.}{a{AA} ya uy ou io ei {AA}e}
+****************** Fin code ******************
+
+
+****************** Code 179 ******************
+\catcode`\@11
+\def\quark{\quark}
+
+\def\multisubst#1#2{% #1 = <code>   #2 = <liste des paires>
+	\def\subst at code{#1}% stocke le <code>
+	\multisubst at i#2\quark\quark% appelle la macro r\xE9cursive avec 
+	                           % 2 arguments sp\xE9ciaux en fin de liste
+}
+
+\def\multisubst at i#1#2{% #1#2 = paire de motifs en cours
+	\def\arg at a{#1}% stocke le <motif1> dans une macro
+	\ifx\arg at a\quark% si le motif sp\xE9cial est atteint
+		\expandafter\subst at code% ex\xE9cuter le code obtenu
+	\else
+		\expandafter\substtocs\expandafter\subst at code\expandafter% 1-d\xE9veloppe
+			{\subst at code}{#1}{#2}% le <code> et effectue la substitution en cours
+		\expandafter\multisubst at i% puis lis la paire de motifs suivants
+	\fi
+}
+\catcode`\@12
+\multisubst{abracadabra}{aA rR}\par
+\multisubst{Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des
+  sonorit\'es catalanes, corses ou grecques assez inattendues.}{a{AA} ya uy ou io ei {AA}e}
+****************** Fin code ******************
+
+
+****************** Code 180 ******************
+\iftrue foobar\else ceci n'est jamais lu par \TeX\fi\par
+\iffalse ceci n'est jamais lu par \TeX\else foobar\fi
+****************** Fin code ******************
+
+
+****************** Code 181 ******************
+\newif\ifhomme
+\def\debutlettre{Ch\ifhomme er Monsieur\else \xE8re Madame\fi}%
+
+\hommetrue
+\debutlettre
+\medbreak
+
+\hommefalse
+\debutlettre
+****************** Fin code ******************
+
+
+****************** Code 182 ******************
+\catcode`\*=13 \catcode`\+=13 % "*" et "+" sont actifs
+1) \def*{xyz}\def+{abc}% d\xE9finit les caract\xE8res actifs
+   \ifcat *+vrai\else faux\fi\qquad 
+2) \ifcat \noexpand *\noexpand +vrai\else faux\fi\qquad
+3) \def\foo{foobar}%
+   \ifcat \noexpand\foo\relax vrai\else faux\fi\qquad% \foo et \relax sont vus \xE9gaux   
+4) \ifcat = vrai\else faux\fi\qquad% "=" et " " n'ont pas le m\xEAme catcode
+5) \ifcat _^vrai\else faux\fi\qquad% "_" et "^" n'ont pas le m\xEAme catcode
+6) \let\foo=&
+   \ifcat &\foo vrai\else faux\fi% "&" et \foo (let-\xE9gal \xE0 "&") sont vus \xE9gaux
+****************** Fin code ******************
+
+
+****************** Code 183 ******************
+\catcode`\@11
+\def\ifcs#1{%
+	\ifcat\noexpand#1\relax\expandafter\firstoftwo
+	\else                  \expandafter\secondoftwo
+	\fi
+}
+\catcode`\@12
+1) \def\foo{bar}\ifcs\foo{vrai}{faux}\qquad
+2) \ifcs\def{vrai}{faux}\qquad
+3) \ifcs A{vrai}{faux}\qquad
+\catcode`\*=13
+4) \let*=W \ifcs*{vrai}{faux}\qquad
+5) \let*=\relax \ifcs*{vrai}{faux}\qquad
+6) \let\foo=A \ifcs\foo{vrai}{faux}\qquad
+7) \ifcs\bgroup{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 184 ******************
+1) \def\foo{xxy}\def\bar{aab}
+   \if\foo\bar vrai\else faux\fi\qquad
+2) \if aA vrai\else faux\fi\qquad% "a" et "A" n'ont pas les m\xEAmes charcode
+3) \if\relax\noexpand\foo vrai\else faux\fi\qquad% \relax et \foo ont un charcode=256
+4) \let\foo=&\if\foo &vrai\else faux\fi\qquad% \foo est vue comme "&"
+5) \if\string~\noexpand~vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 185 ******************
+\catcode`\@11
+\def\ifcs#1{%
+	\begingroup
+		\escapechar=`\@ % prend "@" comme caract\xE8re d'\xE9chappement
+		\if% les premiers caract\xE8res de
+			\expandafter\firstto at nil\string#1a\@nil% "#1a"
+			\expandafter\firstto at nil\string\relax\@nil% et "\relax" sont-ils \xE9gaux ?
+			\endgroup\expandafter\firstoftwo% si oui, fermer le groupe et renvoyer "vrai"
+		\else% sinon, fermer le groupe et renvoyer "faux"
+			\endgroup\expandafter\secondoftwo
+		\fi
+}
+\catcode`\@12
+1) \def\foo{bar}\ifcs\foo{vrai}{faux}\qquad
+2) \ifcs\def{vrai}{faux}\qquad
+3) \ifcs A{vrai}{faux}\qquad
+\catcode`\*=13
+4) \let*=W \ifcs*{vrai}{faux}\qquad
+5) \let*=\relax \ifcs*{vrai}{faux}\qquad
+6) \let\foo=A \ifcs\foo{vrai}{faux}\qquad
+7) \ifcs\bgroup{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 186 ******************
+\edef\specialrelax{\ifnum1=1\fi}
+\meaning\specialrelax
+****************** Fin code ******************
+
+
+****************** Code 187 ******************
+\edef\specialrelax{\ifnum1=1\fi}% texte de remplacement = \relax sp\xE9cial
+\edef\normalrelax{\relax}% texte de remplacement = \relax normal
+\meaning\specialrelax\par
+\meaning\normalrelax\par
+Les 2 \string\relax{} sont \ifx\specialrelax\normalrelax identiques\else diff\xE9rents\fi.
+****************** Fin code ******************
+
+
+****************** Code 188 ******************
+\edef\specialrelax{\ifnum1=1\fi}
+\expandafter\def\specialrelax{foobar}% red\xE9finition un \relax sp\xE9cial
+****************** Fin code ******************
+
+
+****************** Code 189 ******************
+\catcode`\@11
+\def\ifnumcase#1{%
+	\begingroup
+	\def\elseif{\elseif}\def\endif{\endif}% d\xE9finir deux "quarks" locaux
+	\def\nombre@{#1}% stocker le nombre \xE0 comparer dans \nombre@
+	\ifnumcase at i% appeller la macro r\xE9cursive
+}
+
+\def\ifnumcase at i#1{%
+	\def\nxt at arg{#1}% stocker l'argument suivant
+	\ifx\nxt at arg\elseif% si c'est \elseif
+		\def\next at todo{\endgroup\idto at endif}% fermer le groupe et aller \xE0 \idto at endif
+	\else
+		\ifx\nxt at arg\endif% si c'est \endif
+			\let\next at todo\endgroup% fermer le groupe
+		\else
+			\ifnum\nombre@=\nxt at arg% s'il y a \xE9galit\xE9
+				\def\next at todo{\endgroup\firstto at endif}% fermer le groupe puis \firstto at endif
+			\else% sinon
+				\let\next at todo=\ifnumcase at ii% aller \xE0 \ifnumcase at ii
+			\fi
+		\fi
+	\fi
+	\next at todo% ex\xE9cuter l'action d\xE9cid\xE9e ci-dessus
+}
+
+\def\ifnumcase at ii#1{\ifnumcase at i}
+\def\idto at endif#1\endif{#1}
+\def\firstto at endif#1#2\endif{#1}
+\catcode`\@12
+\def\swaptwo#1#2{#2#1}
+\def\testenombre#1{%
+	\ifnumcase{#1}
+		{1}{C'est "un" et je prends le premier argument: \firstoftwo}
+		{3}{J'ai vu un "trois" et je mange les deux arguments : \gobtwo}
+		{15}{L'argument est "15" et je prends le second argument : \secondoftwo}
+	\elseif
+		ni 1, ni 3, ni 5 et j'inverse les deux arguments : \swaptwo
+	\endif
+}
+\testenombre{3}{foo}{bar}\par
+\testenombre{16}{foo}{bar}\par
+\testenombre{15}{foo}{bar}\par
+\testenombre{1}{foo}{bar}
+****************** Fin code ******************
+
+
+****************** Code 190 ******************
+\catcode`\@11
+\def\endif{\endif}\def\elseif{\elseif}% d\xE9finit les quarks
+
+\def\ifnumcase#1#2{% #1=<nombre>   #2=prochain argument
+	\ifx\elseif#2% si #2 est \elseif
+	\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		\idto at endif% aller \xE0 \idto at endif, sinon :
+		{\ifx\endif#2% si #2 est \endif
+		\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			{}% ne rien faire. Sinon #2 est une <valeur i>:
+			{\ifnum#1=#2 % s'il y a \xE9galit\xE9 entre <nombre> et <valeur i>
+			\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+				\firstto at endif% aller \xE0 \firstto at endif
+				{\ifnumcase at i{#1}}% sinon aller \xE0 \ifnumcase at i
+			}%
+		}%
+}
+
+\def\ifnumcase at i#1#2{% #1=<nombre>  #2=<code i> \xE0 suivre qui est mang\xE9
+	\ifnumcase{#1}% retourner \xE0 \ifnumcase en transmettant #1
+}
+
+\def\idto at endif#1\endif{#1}
+\def\firstto at endif#1#2\endif{#1}
+\catcode`\@12
+\def\swaptwo#1#2{#2#1}
+\def\testenombre#1{%
+	\ifnumcase{#1}
+		{1}{C'est "un" et je prends le premier argument: \firstoftwo}
+		{3}{J'ai vu un "trois" et je mange les deux arguments : \gobtwo}
+		{15}{L'argument est "15" et je prends le second argument : \secondoftwo}
+	\elseif
+		ni 1, ni 3, ni 5 et j'inverse les deux arguments : \swaptwo
+	\endif
+}
+\testenombre{3}{foo}{bar}\par
+\testenombre{16}{foo}{bar}\par
+\testenombre{15}{foo}{bar}\par
+\edef\macro{\testenombre{1}{foo}{bar}}\meaning\macro
+****************** Fin code ******************
+
+
+****************** Code 191 ******************
+\catcode`\@11
+\def\endif{\endif}\def\elseif{\elseif}%
+\def\ifxcase#1#2{% #1=<token>   #2=prochain argument
+	\ifx\elseif#2% si #2 est \elseif
+	\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		\idto at endif% aller \xE0 \idto at endif, sinon :
+		{\ifx\endif#2% si #2 est \endif
+		\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			{}% ne rien faire. Sinon #2 est un <token i>:
+			{\ifx#1#2% s'il y a \xE9galit\xE9 entre <token> et <token i>
+			\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+				\firstto at endif% aller \xE0 \firstto at endif
+				{\ifxcase at i{#1}}% sinon aller \xE0 \ifnumcase at i
+			}%
+		}%
+}
+\def\ifxcase at i#1#2{% #1=<token>  #2=<code i> \xE0 suivre (qui est mang\xE9)
+	\ifxcase{#1}% retourner \xE0 \ifxcase en transmettant #1
+}
+\def\idto at endif#1\endif{#1}
+\def\firstto at endif#1#2\endif{#1}
+\catcode`\@12
+\def\testtoken#1{%
+	\ifxcase{#1}
+		a{Le token est "a"}
+		+{J'ai vu un "+"}
+		\relax{L'argument est "\string\relax"}
+	\elseif
+		Tous les tests sont n\xE9gatifs%
+	\endif
+}
+1) \testtoken a\par
+2) \let\foo=a\testtoken\foo\par
+3) \testtoken+\par
+4) \testtoken\relax\par
+5) \edef\foo{\testtoken\relax}\meaning\foo\par
+6) \edef\foo{\testtoken W}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 192 ******************
+\newcount\xx % d\xE9finit un compteur utilis\xE9 dans la boucle
+\def\compte#1{%
+	\xx=0 % initialise le compteur
+	\loop% d\xE9but de la boucle
+		\advance\xx1 % incr\xE9mente le compteur
+		\ifnum\xx<#1 % s'il est inf\xE9rieur \xE0 la borne
+		  \number\xx , % affiche le nombre et la virgule
+	\repeat% et recommence
+	\ifnum#1>0 \number\xx\relax\fi% si le nombre #1 est >0, afficher le dernier nombre
+	}
+a) \compte{1}.\qquad b) \compte{-3}.\qquad c) \compte{7}.
+****************** Fin code ******************
+
+
+****************** Code 193 ******************
+\catcode`\@11
+\newcount\cnt at repeat % d\xE9finit le compteur de \xrepeat
+
+\def\xloop{%
+	\def\xiterate{}% initialiser \xiterate \xE0 vide
+	\cnt at repeat\z@% initialiser le compteur de \xrepeat
+	\xloop at i% aller \xE0 la macro r\xE9cursive
+}
+
+\long\def\xloop at i#1\xrepeat{%
+	\addtomacro\xiterate{#1}% ajoute ce qui est avant le premier \xrepeat
+	\exparg\cnttimestocs{\xiterate}\xloop\cnt at loop
+	% combien de \xloop dans \xiterate
+	\ifnum\cnt at loop=\cnt at repeat\relax
+		\expandafter\firstoftwo\else\expandafter\secondoftwo
+	\fi
+		{% autant que de \xrepeat -> \detokenize pour afficher
+		"\detokenize\expandafter{\xiterate}"%
+		}
+		{\addtomacro\xiterate\xrepeat% sinon, ajouter ce \xrepeat
+		\advance\cnt at repeat by 1% incr\xE9menter le compteutr de \xrepeat
+		\xloop at i% et chercher le prochain \xrepeat
+		}%
+}
+\let\xrepeat\fi
+\catcode`\@12
+\xloop a\xloop b\xloop 12\xrepeat c\xrepeat \xloop X\xrepeat\xrepeat
+****************** Fin code ******************
+
+
+****************** Code 194 ******************
+\catcode`\@11
+\newcount\cnt at repeat
+\newcount\cnt at nested
+\cnt at nested=0 % compteur d'imbrications
+\def\xloop{%
+	\global\advance\cnt at nested by 1 % augmente le compteur d'imbrications
+	\expandafter\def\csname xiterate@\number\cnt at nested\endcsname{}%
+	\cnt at repeat\z@% initialise le compteur de \xrepeat \xE0 0
+	\xloop at i% aller \xE0 la macro \xloop at i
+}
+\long\def\xloop at i#1\xrepeat{%
+	\expandafter\addtomacro\csname xiterate@\number\cnt at nested\endcsname{#1}%
+	\expandafter\expandafter\expandafter\cnttimestocs\expandafter\expandafter\expandafter
+		{\csname xiterate@\number\cnt at nested\endcsname}\xloop\cnt at loop
+	\ifnum\cnt at loop=\cnt at repeat\relax
+		\expandafter\firstoftwo\else\expandafter\secondoftwo
+	\fi
+		{\expandafter\eaddtomacro\csname xiterate@\number\cnt at nested\expandafter\endcsname
+			{\expandafter\expandafter\csname xiterate@\number\cnt at nested\endcsname\fi}%
+		%\expandafter\show\csname xiterate@\number\cnt at nested\endcsname
+		\csname xiterate@\number\cnt at nested\endcsname
+		\letname{xiterate@\number\cnt at nested}\relax
+		\global\advance\cnt at nested by -1
+		}
+		{\expandafter\addtomacro\csname xiterate@\number\cnt at nested\endcsname\xrepeat
+		\advance\cnt at repeat by 1 
+		\xloop at i
+		}%
+}%
+\let\xrepeat\fi
+\catcode`\@12
+
+\newcount\cntxx \cntxx=1 % compteur des lignes
+\newcount\cntyy
+\xloop
+	\cntyy=1 % compteur des colonnes
+	\xloop
+		(\number\cntxx,\number\cntyy)% affiche "(ligne,colonne)"
+		\ifnum\cntyy<5 % tant que colonne<5
+		\advance\cntyy1 % incr\xE9mente colonne
+		, % <- affiche ", "
+	\xrepeat% et recommence
+	\ifnum\cntxx<3 % tant que ligne<3
+	\advance\cntxx1 % incr\xE9mente ligne
+	\par % va \xE0 la ligne
+\xrepeat% et recommence
+****************** Fin code ******************
+
+
+****************** Code 195 ******************
+\catcode`\@11
+\def\end at foreach{\end at foreach}% d\xE9finit un quark
+\long\def\doforeach#1\in#2#3{%
+	\def\loop at code{#3}% assigne le <code> \xE0 \loop at code
+	% appel \xE0 \doforeach at i : mettre la macro #1 en premier, puis la liste de valeurs #2
+	\doforeach at i#1#2,\end at foreach,% ajouter \xE0 la fin ",\end at foreach,"
+	% une fois les boucles finies, neutraliser les macros d\xE9j\xE0 d\xE9finies
+	\let#1\relax \let\loop at code\relax
+}
+
+\long\def\doforeach at i#1#2,{% #1=\<macro>  #2=valeur courante
+	\def#1{#2}% stocke la valeur en cours dans la \<macro>
+	\unless\ifx\end at foreach#1% si \end at foreach n'est pas atteint
+		\antefi% am\xE8ne le \fi ici
+		\loop at code% ex\xE9cute le code
+		\doforeach at i#1% et recommencer
+	\fi
+}
+\catcode`@12
+\doforeach\x\in{a,bcd,{efg},hi}{\meaning\x.\par}
+****************** Fin code ******************
+
+
+****************** Code 196 ******************
+\catcode`\@11
+\def\end at foreach{\end at foreach}
+\def\defseplist#1{%
+	\long\def\doforeach##1\in##2##3{%
+		\def\loop at code{##3}% assigne le <code> \xE0 \loop at code
+		\doforeach at i##1##2#1\end at foreach#1% ajouter ",\end at foreach," et aller \xE0 \doforeach at i
+		% apr\xE8s \xEAtre sorti des boucles, neutraliser les macros d\xE9j\xE0 d\xE9finies
+		\let\loop at code\relax \let##1\relax
+	}%
+	\long\def\doforeach at i##1##2#1{%
+		\def##1{##2}% stocke la valeur en cours dans la \<macro>
+		\unless\ifx\end at foreach##1% si la fin n'est pas atteinte
+			\antefi% am\xE8ne le \fi ici
+			\loop at code% ex\xE9cute le code
+			\doforeach at i##1% et recommencer
+		\fi
+	}%
+}
+\defseplist{,}% d\xE9finit les macros avec le s\xE9parateur par d\xE9faut
+\catcode`@12
+
+\doforeach\x\in{a,bcd,efg}{Argument courant : "\x".\par}\medbreak
+
+\defseplist{--}% s\xE9parateur "--"
+\doforeach\nn\in{4,19--0,5--8,575}{Nombre lu : "\nn"\par}
+****************** Fin code ******************
+
+
+****************** Code 197 ******************
+\catcode`\@11
+\newcount\cnt at nest \cnt at nest=0 % d\xE9finit et initialise le compteur d'imbrication
+\def\end at foreach{\end at foreach}
+
+\def\defseplist#1{%
+	\long\def\doforeach##1\in##2##3{%
+		\global\advance\cnt at nest1 % entr\xE9e de boucle : incr\xE9menter le compteur d'imbrication
+		\defname{loop at code@\number\cnt at nest}{##3}% assigne le <code> \xE0 \loop at code@<n>
+		\doforeach at i##1##2#1\end at foreach#1% ajouter ",\end at foreach," et aller \xE0 \doforeach at i
+		% une fois fini :
+		\let##1\empty% dans ce cas, neutraliser les macros d\xE9j\xE0 d\xE9finies
+		\letname{loop at code@\number\cnt at nest}\empty%
+		\global\advance\cnt at nest-1 %sortie de boucle : d\xE9cr\xE9menter le compteur d'imbrication
+	}%
+	\long\def\doforeach at i##1##2#1{%
+		\def##1{##2}% stocke la valeur en cours dans la \<macro>
+		\unless\ifx\end at foreach##1% tant que la fin n'est pas atteinte
+			\antefi% am\xE8ne le \fi ici
+			\csname loop at code@\number\cnt at nest\endcsname% ex\xE9cute le code
+			\doforeach at i##1% et recommencer
+		\fi
+	}%
+}
+\catcode`@12
+\defseplist{,}
+
+\doforeach\xxx\in{1,2,3}{%
+	Ligne \xxx{} : \doforeach\yyy\in{a,b,c,d,e}{(\xxx,\yyy)}.\par
+}
+****************** Fin code ******************
+
+
+****************** Code 198 ******************
+\catcode`\@11
+\newcount\cnt at nest \cnt at nest=0 % d\xE9finit et initialise le compteur d'imbrication
+\def\end at foreach{\end at foreach}
+\long\def\save at macro#1{% sauvegarde la macro #1
+	\ifdefined#1% si la macro #1 est d\xE9j\xE0 d\xE9finie...
+		\letname{saved at var@\number\cnt at nest}#1% ...la sauvegarder
+	\fi
+}
+\long\def\restore at macro#1{% restaure la macro #1
+% le \csname donne \relax si la sauvegarde n'a pas \xE9t\xE9 faite
+	\expandafter\let\expandafter#1\csname saved at var@\number\cnt at nest\endcsname
+}
+\def\defseplist#1{%
+	\long\def\doforeach##1\in##2##3{%
+		\global\advance\cnt at nest1 % entr\xE9e de boucle : incr\xE9menter le compteur d'imbrication
+		\save at macro##1% sauvegarde la macro ##1
+		\defname{loop at code@\number\cnt at nest}{##3}% assigne le <code> \xE0 \loop at code@<n>
+		\doforeach at i##1##2#1\end at foreach#1% ajouter ",\end at foreach," et aller \xE0 \doforeach at i
+		% une fois fini, neutraliser la macro contenant le <code>
+		\letname{loop at code@\number\cnt at nest}\empty
+		\restore at macro##1% restaurer la \<macro>
+		\global\advance\cnt at nest-1 % et d\xE9cr\xE9menter le compteur d'imbrication
+	}%
+	\long\def\doforeach at i##1##2#1{%
+		\def##1{##2}% stocke la valeur en cours dans la \<macro>
+		\unless\ifx\end at foreach##1% si la fin n'est pas atteinte
+			\antefi% am\xE8ne le \fi ici
+			\csname loop at code@\number\cnt at nest\endcsname% ex\xE9cute le code
+			\doforeach at i##1% et recommencer
+		\fi%
+	}%
+}
+\catcode`@12
+\defseplist{,}
+\doforeach\par\in{a,b,c,y,z}{$\par_i$}
+
+\meaning\par% \par doit \xEAtre redevenu une primitive
+
+\doforeach\xxx\in{1,2,3}{%
+	Ligne \xxx{} : \doforeach\yyy\in{a,b,c,d,e}{(\xxx,\yyy)}.\par
+}
+****************** Fin code ******************
+
+
+****************** Code 199 ******************
+\let\foo=\djfhdsldv% \foo est rendue \let-\xE9gale \xE0 une macro ind\xE9finie
+a) \meaning\foo\par
+% puis \djfhdsldv est rendue \let-\xE9gale \xE0 \foo (ou \foo est construit avec \csname)
+\expandafter\let\expandafter\djfhdsldv\csname foo\endcsname
+b) \meaning\djfhdsldv
+****************** Fin code ******************
+
+
+****************** Code 200 ******************
+\catcode`\@11
+\newcount\cnt at nest \cnt at nest=0 % d\xE9finit et initialise le compteur d'imbrication
+\def\end at foreach{\end at foreach}
+\long\def\save at macro#1#2{\letname{saved at var@\number\cnt at nest#1}#2}
+\long\def\save at macro@i#1/#2{\save at macro{a}#1\save at macro{b}#2}
+\long\def\restore at macro#1#2{%
+	\expandafter\let\expandafter#2\csname saved at var@\number\cnt at nest#1\endcsname
+}
+\long\def\restore at macro@i#1/#2{\restore at macro{a}#1\restore at macro{b}#2}
+\def\defseplist#1{%
+	\long\def\doforeach##1\in##2##3{%
+		\global\advance\cnt at nest1 % entr\xE9e de boucle : incr\xE9menter le compteur d'imbrication
+		\global\let\allow at recurse\identity% permet l'appel r\xE9cursif plus bas
+		\ifin{##1}{/}% si ##1 contient "/"
+			{\save at macro@i##1% sauvegarde les macros
+			\doforeach at ii% appeler la macro r\xE9cursive avec les arguments
+				{##3}% 1) code \xE0 ex\xE9cuter
+				##1%   2) variables sous la forme \<macro1>/\<macro2>
+				##2#1\end at foreach/\end at foreach#1% puis la liste ##2 suivie de
+				                                % ",\end at foreach/\end at foreach,"
+			\restore at macro@i##1% une fois sorti de toutes les boucles, restaurer les macros
+			}% si ##1 ne contient pas "/"
+			{\save at macro{}##1% sauvegarde la macro
+			\doforeach at i% appeler la macro r\xE9cursive
+				{##3}% mettre en premier le <code>
+				##1% puis la variable ##1 en 2e position
+				##2#1\end at foreach#1% enfin la liste ##2 suivie de ",\end at foreach,"
+			\restore at macro{}##1% une fois sorti de toutes les boucles, restaurer la macro
+			}%
+		\global\advance\cnt at nest-1 % d\xE9cr\xE9mente le compteur d'imbrications
+	}%
+	% ##1 = code \xE0 ex\xE9cuter, ##2= variable, ##3=valeur courante
+	\long\def\doforeach at i##1##2##3#1{%
+		\ifx\end at foreach##3% si la fin est atteinte
+		\expandafter\gobone\else\expandafter\identity\fi% manger sinon ex\xE9cuter:
+			{\def##2{##3}% fait l'assignation \xE0 la variable
+			##1% le code puis
+			\allow at recurse{\doforeach at i{##1}##2}% recommencer
+			}%
+	}%
+	% ##1 = code \xE0 ex\xE9cuter, ##2/##3= variables, ##4/##5=valeurs courantes
+	\long\def\doforeach at ii##1##2/##3##4/##5#1{%
+		\ifx\end at foreach##4% si la fin est atteinte
+		\expandafter\gobone\else\expandafter\identity\fi% manger sinon ex\xE9cuter:
+			{\def##2{##4}\def##3{##5}% fait l'assignation des deux variables
+			##1% le code puis
+			\allow at recurse{\doforeach at ii{##1}##2/##3}% recommencer
+			}%
+	}%
+	% macro qui, si elle remplace \allow at recurse, annule l'appel r\xE9cursif
+	\long\def\forbid at recurse##1\end at foreach#1{}% tout manger jusqu'\xE0 "\end at foreach,"
+}
+\def\doforeachexit{\global\let\allow at recurse\forbid at recurse}
+\catcode`\@12
+\defseplist{,}
+\doforeach\par\in{a,b,c,y,z}{$\par_i$}\medskip
+
+\doforeach\sujet/\terminaison\in{Je/e,Tu/es,Il/e,Nous/ons,Vous/ez,Ils/ent}
+	{\sujet\ programm\terminaison{} en \TeX\par}\medskip
+
+Les voyelles lues sont :
+\doforeach\ii\in{a,e,i,o,u,y}{\ii\if o\ii\doforeachexit\fi}.\medskip
+
+\doforeach\xx\in{a,b,c,d,e,f}
+	{\doforeach\ii\in{1,2,3,4}{\xx\ii{} \ifnum\ii=3 \doforeachexit\fi}\par}
+****************** Fin code ******************
+
+
+****************** Code 201 ******************
+\newdimen\dimA \newdimen\dimB% alloue deux registres de dimension
+a) \dimA=59.5pt
+   \the\dimA\qquad% doit afficher 59.5pt
+b) \dimA=1.5cm
+   \the\dimA\qquad% convertit \xE0 l'affichage 1.5cm en pt
+c) \dimB=7pt % assigne 7pt \xE0 \dimB
+   \dimA\dimB% rend \dimA \xE9gal \xE0 dimB
+   \the\dimA\qquad
+d) \dimA=6\dimB% rend \dimA \xE9gal \xE0 6 fois \dimB
+   \the\dimA
+****************** Fin code ******************
+
+
+****************** Code 202 ******************
+\newdimen\foo
+\foo=25pt % assigne 25pt au registre \foo
+\divide\foo 4 % le multiplie par 4
+\advance\foo1.72pt % lui ajoute 1.72pt
+\multiply\foo3 % le multiplie par 3
+\the\foo% affiche la dimension obtenue
+****************** Fin code ******************
+
+
+****************** Code 203 ******************
+\begingroup% ouvrir un groupe
+	\edef\temp{\endgroup\def\noexpand\removept##1.##2\string p\string t}%
+\temp{#1\ifnum#2>0 .#2\fi}% et le fermer avant de d\xE9finir \removept
+\newdimen\foo
+a) \foo=15pt \expandafter\removept\the\foo\qquad
+b) \foo=3.14pt \expandafter\removept\the\foo
+****************** Fin code ******************
+
+
+****************** Code 204 ******************
+\def\dimtodec{\expandafter\removept\the}
+\newdimen\foo
+a) \foo=15pt \dimtodec\foo \qquad
+b) \foo=3.14pt \dimtodec\foo
+****************** Fin code ******************
+
+
+****************** Code 205 ******************
+a) \the\dimexpr 1cm + 0.5cm\relax \qquad
+b) \the\dimexpr 1pt + 1pt\relax \qquad
+c) \the\dimexpr 1pt + 2pt * 3\relax\qquad
+d) \the\dimexpr (1pt + 2pt) * 3\relax\qquad
+e) \the\dimexpr (1.2pt + 0.8pt) * 5\relax\qquad
+f) \newdimen\foo \foo=15pt 
+   \the\dimexpr\foo-(\foo + 1pt) / 4\relax
+****************** Fin code ******************
+
+
+****************** Code 206 ******************
+\the\dimexpr0,7pt + 0.4pt\relax
+****************** Fin code ******************
+
+
+****************** Code 207 ******************
+a) \newdimen\foodim \foodim=1cm \number\foodim\relax\qquad
+b) \number\dimexpr 0.7pt + 0.4pt\relax\qquad
+c) \number\dimexpr 1.1pt\relax
+****************** Fin code ******************
+
+
+****************** Code 208 ******************
+\catcode`\@11
+\def\FOR#1=#2to#3\do#4#{%
+	\ifempty{#4}
+		{\let\FOR at increment\z@}
+		{\edef\FOR at increment{\the\dimexpr#4pt\relax}}% lit et normalise l'argument optionnel
+	\ifdim\FOR at increment=\z@% s'il est nul,
+		\edef\FOR at increment{% le red\xE9finir \xE0 -1pt (si #3<#2) et 1pt sinon
+			\ifdim\dimexpr#3pt-#2pt\relax<\z@ -1\else 1\fi pt
+		}% \FOR at increment vaut donc 1 ou -1
+	\fi
+	\ifdim\dimtodec\dimexpr#3pt-#2pt\relax\dimexpr\FOR at increment\relax<\z@
+		\expandafter\gobone% si argument optionnel incompatible, manger le {<code>}
+	\else
+		\edef#1{\dimtodec\dimexpr#2pt\relax}% initialise la \<macro>
+		\edef\macro at args{% d\xE9finit et d\xE9veloppe les arguments \xE0 passer \xE0 \FOR at i
+			%#1=nom de la macro r\xE9cursive :
+			\expandafter\noexpand\csname FOR at ii@\string#1\endcsname
+			\ifdim\FOR at increment<\z@ <\else >\fi% #2=signe de comparaison
+			{\FOR at increment}% #3=incr\xE9ment
+			\noexpand#1% #4=\<macro>
+			{\the\dimexpr#3pt\relax}% #5=dimension n2
+		}%
+		\antefi% externalise la ligne ci-dessous de la port\xE9e du test
+		\expandafter\FOR at i\macro at args% appelle \FOR at i avec les arguments d\xE9finis ci-dessus
+	\fi
+}
+
+% #1=nom de la macro r\xE9cursive de type "\FOR at ii@\<macro>"
+% #2=signe de comparaison  % #3=incr\xE9ment
+% #4=\<macro>  % #5=dimension n2  % #6=<code> \xE0 ex\xE9cuter
+\long\def\FOR at i#1#2#3#4#5#6{%
+	\def#1{% d\xE9finit la sous macro r\xE9cursive
+		\unless\ifdim#4pt#2#5\relax% tant que la \<macro> variable n'a pas d\xE9pass\xE9 n2
+			\afterfi{% rendre la r\xE9cursivit\xE9 terminale
+				#6% ex\xE9cute le code
+				\edef#4{\dimtodec\dimexpr#4pt+#3\relax}% incr\xE9mente la \<macro>
+				#1% recommence
+			}%
+		\fi
+	}%
+	#1% appelle la sous-macro r\xE9cursive
+}%
+\def\exitFOR#1{% #1=\<macro> correspondant \xE0 la boucle de laquelle on veut sortir
+	\defname{FOR at ii@\string#1}{}%
+}
+
+\def\ifexitFOR#1{% envoie vrai si on est pr\xE9matur\xE9ment sorti de la boucle de \<macro> #1
+	% si la macro r\xE9cursive est \empty
+	\expandafter\ifx\csname FOR at ii@\string#1\endcsname\empty
+		\expandafter\firstoftwo% c'est qu'on est sortir pr\xE9matur\xE9ment, renvoyer "vrai"
+	\else
+		\expandafter\secondoftwo% sinon, renvoyer "faux"
+	\fi
+}
+\catcode`\@=12
+a) \FOR\xx=1.5 to -5\do-1{"\xx" }\par
+
+b) \FOR\ii=1 to 2.742\do.25{"\ii" }\par
+
+c) \FOR\ii=0 to 1\do0.1{"\ii" \ifdim\ii pt>0.5pt \exitFOR\ii\fi}
+****************** Fin code ******************
+
+
+****************** Code 209 ******************
+\newdimen\foo
+\foo=15.2pt \foo=1.5\foo \the\foo% vaut 15.2*1.5
+****************** Fin code ******************
+
+
+****************** Code 210 ******************
+\catcode`\@11
+\newdimen\dim at a
+\def\decmul#1#2{%
+	\dim at a=#2pt    % range la dimension #2pt dans le registre de dimension
+	\dim at a=#1\dim at a% multiplier le registre par le d\xE9cimal #1
+	\dimtodec\dim at a% convertir la dimension en d\xE9cimal
+}
+\catcode`\@12
+a) \decmul{15.2}{1.5}\qquad
+b) \decmul{48.2}{.375}
+****************** Fin code ******************
+
+
+****************** Code 211 ******************
+\def\decmul#1#2{\dimtodec\dimexpr#1\dimexpr#2pt\relax\relax}
+
+a) \decmul{15.2}{1.5}\qquad
+b) \edef\foo{\decmul{48.2}{.375}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 212 ******************
+\def\decdiv#1#2{% divise le d\xE9cimal #1 par le d\xE9cimal #2
+	\dimtodec
+	\dimexpr
+		\numexpr
+			\dimexpr #1pt \relax * 65536 / \dimexpr #2pt \relax
+		\relax
+		sp
+	\relax
+}
+
+1) \decdiv{4.5}{0.075}\qquad% doit donner 60
+2) \decdiv{8}{0.1}\qquad% doit donner 80
+3) \decdiv{3.14}{1.6}\qquad% doit donner 1.9625
+4) \decdiv{687.59829}{5.29871}\qquad% doit donner 129.76706
+4) \edef\foo{\decdiv{0.37}{2.5}}\foo% doit donner 0.148
+****************** Fin code ******************
+
+
+****************** Code 213 ******************
+\def\convertunit#1#2{%
+	\dimtodec
+	\dimexpr
+		\numexpr
+			\dimexpr #1 \relax * 65536 / \dimexpr 1#2 \relax
+		\relax
+		sp
+	\relax
+}
+
+a) \convertunit{15cm}{mm}\qquad
+b) \convertunit{9,14in}{cm}\qquad
+c) \convertunit{100000sp}{mm}\qquad
+d) \convertunit{160.5pt}{cm}\qquad
+e) \edef\foo{\convertunit{2,5cm}{cc}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 214 ******************
+\the\glueexpr 5pt plus 2pt minus 1.5pt + 7pt plus0.5pt minus 3pt\relax \par
+\the\glueexpr 25pt plus2fil + 35pt plus 0.1fill\relax
+****************** Fin code ******************
+
+
+****************** Code 215 ******************
+foo% les caract\xE8res font entrer TeX en mode horizontal
+\kern0.5cm % espace ins\xE9r\xE9e en mode horizontal
+bar\par% \par fait passer en mode vertical
+\kern0.5cm % espace ins\xE9r\xE9e en mode vertical
+boo
+****************** Fin code ******************
+
+
+****************** Code 216 ******************
+Une premi\xE8re ligne\par
+\nointerlineskip% n'ins\xE8re pas de ressort d'interligne ici
+Un second paragraphe constitu\xE9 de plusieurs lignes.
+Un second paragraphe constitu\xE9 de plusieurs lignes.
+Un second paragraphe constitu\xE9 de plusieurs lignes.
+\par% le ressort d'interligne sera ins\xE9r\xE9 ici
+Une derni\xE8re ligne
+****************** Fin code ******************
+
+
+****************** Code 217 ******************
+\begingroup
+\offinterlineskip
+La macro \litterate-\offinterlineskip-, en modifiant de fa\xE7on appropri\xE9e les trois
+primitives \litterate-\baselineskip-, \litterate-\lineskip- et
+\litterate-\lineskiplimit-, rend les boites cons\xE9cutives jointives.
+
+On peut constater dans ces deux paragraphes o\xF9 \litterate-\offinterlineskip- a \xE9t\xE9
+appel\xE9e, que les lignes sont plac\xE9es verticalement au plus pr\xE8s les unes des autres ce
+qui rend la lecture tr\xE8s p\xE9nible et d\xE9montre que le ressort d'interligne est une
+n\xE9cessit\xE9 typographique !\par
+\endgroup
+D\xE9sactiver le ressort d'interligne ne se justifie que lorsque l'on doit composer
+des boites contenant autre chose que du texte, sauf \xE0 vouloir des effets
+typographiques sp\xE9ciaux.
+****************** Fin code ******************
+
+
+****************** Code 218 ******************
+\baselineskip=12pt
+d\xE9but \vtop{\hbox{ligne du haut ligne du haut ligne du haut}
+\hbox{ligne du bas ligne du bas ligne du bas}
+}
+\par
+Et la suite du texte suite du texte suite du texte
+****************** Fin code ******************
+
+
+****************** Code 219 ******************
+\baselineskip=12pt
+d\xE9but \vtop{\hbox{ligne du haut ligne du haut ligne du haut}
+\hbox{ligne du bas ligne du bas ligne du bas}
+\xdef\sprevdepth{\the\prevdepth}% sauvegarde la valeur de \prevdepth
+}
+\par\prevdepth=\sprevdepth\relax% ment sur la boite pr\xE9c\xE9dente
+Et la suite du texte suite du texte suite du texte
+****************** Fin code ******************
+
+
+****************** Code 220 ******************
+\def\dummytext{Voici un texte qui ne rev\xEAt aucune importance
+	et dont le seul but est de meubler artificiellement un paragraphe. }
+\begingroup% \xE0 l'int\xE9rieur d'un groupe,
+	\leftskip=0pt plus 0.5\hsize\relax
+	\rightskip=\leftskip\relax % modifier les ressort d'extr\xE9mit\xE9s
+	\spaceskip=0.3em plus 0.05em\relax% dimension de l'espace intermot
+	\parfillskip=0pt \relax% annuler le ressort de fin de paragraphe
+	\dummytext\dummytext\dummytext% corps du paragraphe
+	\par% compose la paragraphe courant
+	Juste une phrase%
+	\par% compose la paragraphe courant
+\endgroup% avant de sortir du groupe
+****************** Fin code ******************
+
+
+****************** Code 221 ******************
+\def\narrowtext{%
+	\par
+	\begingroup
+		\advance\leftskip 0.1\hsize
+		\advance\rightskip 0.1\hsize
+}
+\def\endnarrowtext{\par\endgroup}
+\def\dummytext{Ceci est un texte sans
+ importance destin\xE9 \xE0 meubler un paragraphe. }
+
+\dummytext\dummytext\dummytext
+\narrowtext
+	\dummytext\dummytext\dummytext
+ \narrowtext
+		\dummytext\dummytext\dummytext
+ \endnarrowtext
+	\dummytext\dummytext\dummytext
+\endnarrowtext
+****************** Fin code ******************
+
+
+****************** Code 222 ******************
+a) \hfill Composition au fer \xE0 droite\par
+b) Composition au fer \xE0 gauche\hfill\kern0pt\par
+c) \hfill Centrage\hfill\kern0pt\par
+d) Des \hfill mots\hfill r\xE9guli\xE8rement\hfill espac\xE9s
+****************** Fin code ******************
+
+
+****************** Code 223 ******************
+a% le caract\xE8re "a" fait passer en mode horizontal
+\hbox{b}c\hbox{d}% les \hbox sont ajout\xE9es en mode horizontal
+\medbreak
+...\xE0 comparer avec...
+\medbreak
+a \par% \par fait passer en mode vertical
+\hbox{b}% \hbox est ajout\xE9e \xE0 la liste verticale
+c% "c" fait passer en mode horizontal
+\hbox{d}% la \hbox est ajout\xE9e en mode horizontal
+****************** Fin code ******************
+
+
+****************** Code 224 ******************
+Ligne de base : .........%
+\vbox{\hbox{ligne du haut}\hbox{ligne du milieu}\hbox{ligne du bas}}%
+.........%
+\vtop{\hbox{ligne du haut}\hbox{ligne du milieu}\hbox{ligne du bas}}.........
+****************** Fin code ******************
+
+
+****************** Code 225 ******************
+\def\dummytext{Bla, bla, bla, un texte sans importance. }
+Ligne de base.........%
+\vbox{\hsize=4cm \dummytext\dummytext}%
+.........%
+\vtop{\hsize=4cm \dummytext\dummytext}.........
+****************** Fin code ******************
+
+
+****************** Code 226 ******************
+\newbox\foobox
+a) \setbox\foobox=\hbox{foobar}% registre non vide
+   Le registre est \ifvoid\foobox vide\else non vide\fi\par
+b) \setbox\foobox=\hbox{foobar}
+   "\box\foobox" et le registre est \ifvoid\foobox vide\else non vide\fi\par
+c) \setbox\foobox=\hbox{foobar}
+   "\copy\foobox" et le registre est \ifvoid\foobox vide\else non vide\fi\par
+d) \setbox\foobox=\hbox{}
+   Le registre est \ifvoid\foobox vide\else non vide\fi
+****************** Fin code ******************
+
+
+****************** Code 227 ******************
+\newbox\foobox
+\setbox\foobox=\hbox{Programmer est facile.}
+<<\copy\foobox>>
+mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut.
+\medbreak
+
+\setbox\foobox=\vbox{\hbox{Programmer}\hbox{est}\hbox{facile.}}
+<<\copy\foobox>>
+mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut.
+\medbreak
+
+\setbox\foobox=\vtop{\hbox{Programmer}\hbox{est}\hbox{facile.}}
+<<\copy\foobox>>
+mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut.
+****************** Fin code ******************
+
+
+****************** Code 228 ******************
+\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}
+a) \setbox\foobox=\vbox{\hbox{Programmer}\hbox{est}\hbox{facile.}}
+   Verticalit\xE9 de la \litterate-\vbox- = \the\vdim\foobox\par
+b) \setbox\foobox=\vtop{\hbox{Programmer}\hbox{est}\hbox{facile.}}
+   Verticalit\xE9 de la \litterate-\vtop- = \the\vdim\foobox
+****************** Fin code ******************
+
+
+****************** Code 229 ******************
+\def\countallchar#1{%
+	Il y a %
+	\setbox0=\hbox{\tt#1}% met #1 dans la boite
+	\edef\arglength{\number\wd0 }% stocke la largeur de la boite en sp
+	\setbox0=\hbox{\tt A}% met "A" dans la boite
+	\edef\charlength{\number\wd0 }% stocke la largeur d'un caract\xE8re
+	$\number\arglength/\charlength % affiche la division
+	=\number\numexpr\arglength/\charlength\relax$ % affiche le quotient
+	caract\xE8res%
+}
+\countallchar{abcd efgh}\par
+\countallchar{A5 xW5 64 a1}\par
+\countallchar{affligeant}
+****************** Fin code ******************
+
+
+****************** Code 230 ******************
+\catcode`@11
+\def\countchar#1#2{%
+		\setbox\z@\hbox{\tt#2}% met #2 dans boite 0
+		\edef\len at a{\number\wd\z@}% mesure la boite
+		\setbox\z@\hbox{\tt\substin{#2}{#1}{}}% recommencer sans "#1"
+		\edef\len at b{\number\wd\z@}% mesure la boite
+		\setbox\z@\hbox{\tt A}% met "A" dans la boite
+		\edef\charlength{\number\wd\z@}% stocke la largeur du caract\xE8re
+		\number\numexpr(\len at a-\len at b)/\charlength% et affiche le quotient
+}
+\catcode`@12
+a) \countchar{a}{abracadabra}\qquad
+b) \countchar{b}{zigzag}\qquad
+c) \countchar{ }{a bc de f ghi j k }
+****************** Fin code ******************
+
+
+****************** Code 231 ******************
+Programmer \raise1ex\hbox{en} \lower1ex\hbox{\TeX} \lower2ex\hbox{est} facile.
+****************** Fin code ******************
+
+
+****************** Code 232 ******************
+\def\cbox#1{%
+	\setbox0\vbox{#1}% met le contenu dans une \vbox
+	\lower\dimexpr(\ht0-\dp0)/2\relax\box0 % l'abaisse
+}
+
+......\cbox{\hbox{$x^2$}}......\cbox{\hbox{foo}\hbox{et bar}}......%
+\cbox{\hbox{Programmer}\hbox{en \TeX}\hbox{est facile}}.......
+****************** Fin code ******************
+
+
+****************** Code 233 ******************
+......\cbox{\hbox{foo}\hbox{et bar}}......$\vcenter{\hbox{foo}\hbox{et bar}}$......
+****************** Fin code ******************
+
+
+****************** Code 234 ******************
+\def\htmath{\begingroup
+	\setbox0=\hbox{$\vcenter{}$}\the\ht0 
+\endgroup
+}
+L'axe math\xE9matique se trouve \xE0 \htmath{} de la ligne de base.
+****************** Fin code ******************
+
+
+****************** Code 235 ******************
+1) \hbox{foobar}\par
+2) \hbox spread 5pt{foo\hfil bar}\par
+3) \hbox spread10pt{foo\hfil bar}
+****************** Fin code ******************
+
+
+****************** Code 236 ******************
+foobar|\rlap{/////}123456\qquad foobar|\llap{/////}123456
+****************** Fin code ******************
+
+
+****************** Code 237 ******************
+\def\clap#1{\hbox to0pt{\hss#1\hss}}
+a) avant la macro|\clap{SURIMPRESSION}apr\xE8s la macro\medbreak
+b) avant la macro|\raise2.5ex\clap{Au-dessus}\lower2.5ex\clap{Au-dessous}%
+   apr\xE8s la macro\medbreak
+c) avant la macro|\raise2.5ex\llap{Au-dessus avant}\lower2.5ex\rlap{Au-dessous apr\xE8s}%
+   apr\xE8s la macro
+****************** Fin code ******************
+
+
+****************** Code 238 ******************
+\setbox0=\hbox{\tt//////////}
+\wd0=0pt % fait croire \xE0 TeX que la larguer de la boite est nulle
+Voici \copy0 du texte partiellement barr\xE9...
+****************** Fin code ******************
+
+
+****************** Code 239 ******************
+\def\printdim{largeur=\the\wd0 \qquad hauteur=\the\ht0 \qquad profondeur = \the\dp0 }
+\setbox0=\hbox{Programmer en \TeX{} est facile}
+a) \printdim\par
+b) \wd0=0pt \ht0=0pt \dp0=0pt% rend toutes le dimensions nulles
+   \printdim\par
+c) \setbox0=\hbox{\unhbox0 }% reprend les dimensions d'origine
+   \printdim
+****************** Fin code ******************
+
+
+****************** Code 240 ******************
+\setbox0=\hbox{}% le registre 0 contient une boite vide
+Le registre \ifvoid0 est vide\else n'est pas vide\fi
+****************** Fin code ******************
+
+
+****************** Code 241 ******************
+\catcode`\@11
+\def\ifzerodimbox#1{% #1=registre de boite
+% revoie vrai si le registre est vide ou contient une boite de dimensions nulles
+	\csname% former la macro "\firstoftwo" ou "\secondoftwo"
+	\ifvoid#1first%% si le registre est vide "first"
+	\else% sinon
+		\ifdim\wd#1=\z@% si la largeur
+			\ifdim\ht#1=\z@% la hauteur
+				\ifdim\dp#1=\z@ first% et la profondeur=0pt, "first"
+				\else second% dans les autres cas "second"
+				\fi
+			\else second%
+			\fi
+		\else second%
+		\fi
+	\fi
+	oftwo% compl\xE9ter avec "oftwo"
+	\endcsname
+}
+\catcode`\@12
+a) \setbox0=\hbox{}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+b) \box0 % affiche la boite vide, le registre est maintenant "void"
+   \ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+c) \setbox0=\hbox{x}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+d) \wd0=0pt \ht0=0pt \dp0=0pt % rend toutes les dimensions nulles
+   \ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+e) \setbox0=\vbox{}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)
+****************** Fin code ******************
+
+
+****************** Code 242 ******************
+\def\ifvoidorempty#1{% teste si le registre #1 est vide ou contient une boite vide
+	\ifvoid#1\relax
+		\expandafter\firstoftwo
+	\else
+		\begingroup% dans un groupe
+			\setbox0=% affecter \xE0 la boite 0
+				\ifhbox#1\hbox\bgroup\unhcopy% un boite horizontale
+				\else    \vbox\bgroup\unvcopy% ou verticale
+				\fi% dans laquelle on compose
+				#1\relax% #1 en dimensions naturelles
+				\expandafter\egroup% sauter la fin de la boite
+				\expandafter% et le \endgroup
+		\endgroup
+		\ifnum\lastnodetype=-1 % et tester si le dernier noeud est vide
+			\expandafter\expandafter\expandafter\firstoftwo
+		\else
+			\expandafter\expandafter\expandafter\secondoftwo
+		\fi
+	\fi
+}
+a) \setbox0=\hbox{}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+b) \box0 % affiche la boite vide, le registre est maintenant "void"
+   \ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+c) \setbox0=\hbox{x}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+d) \wd0=0pt \ht0=0pt \dp0=0pt % rend toutes les dimensions nulles
+   \ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+e) \setbox0=\vbox{}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)
+****************** Fin code ******************
+
+
+****************** Code 243 ******************
+\newdimen\hmaxsize
+\def\cvtop#1{%
+	\hmaxsize=-\maxdimen% initialise \xE0 la plus petite longueur
+	\doforeach\htext\in{#1}% pour chaque \xE9l\xE9ment :
+		{\setbox0=\hbox{\htext}% stocker l'\xE9l\xE9ment "\htext" dans une \hbox
+		\ifdim\wd0 >\hmaxsize% si sa longueur est sup\xE9rieure \xE0 \hmaxsize
+			\hmaxsize=\wd0 % mettre \xE0 jour \hmaxsize
+		\fi
+		}%
+	\vtop{% dans une \vtop...
+		\doforeach\htext\in{#1}% pour chaque \xE9l\xE9ment :
+			{\hbox to\hmaxsize{\hss\htext\hss}% le centrer dans une \hbox de longueur \hmaxsize
+			}%
+	}%
+}
+
+texte avant...\cvtop{Ligne du haut,Tr\xE8s grande ligne du milieu,Ligne du bas pour finir}%
+...texte apr\xE8s
+****************** Fin code ******************
+
+
+****************** Code 244 ******************
+\newdimen\hmaxsize
+\def\cvtop#1{%
+	\hmaxsize=-\maxdimen% initialise \xE0 la plus petite longueur
+	\doforeach\htext\in{#1}% pour chaque \xE9l\xE9ment :
+		{\setbox0=\hbox{\htext}% stocker l'\xE9l\xE9ment "\htext" dans une \hbox
+		\ifdim\wd0 >\hmaxsize% si sa longueur est sup\xE9rieure \xE0 \hmaxsize
+			\hmaxsize=\wd0 % mettre \xE0 jour \hmaxsize
+		\fi
+		}%
+	\vtop{% dans une \vtop...
+		\hsize\hmaxsize % longueur de la \vtop = \maxhsize
+		\parindent=0pt % pas d'indentation
+		\leftskip=0pt plus1fil minus0pt \rightskip=\leftskip% ressorts de centrage
+		\doforeach\htext\in{#1}% pour chaque \xE9l\xE9ment :
+			{\htext\par}% le composer et finir le paragraphe
+	}%
+}
+
+texte avant...\cvtop{Ligne du haut,Tr\xE8s grande ligne du milieu,Ligne du bas pour finir}%
+...texte apr\xE8s
+****************** Fin code ******************
+
+
+****************** Code 245 ******************
+\halign{X#**\ignorespaces&#&\hfil #\cr % pr\xE9ambule
+foo            &foo bar&123 456\cr % premi\xE8re ligne
+deuxi\xE8me ligne &1      &12\cr % deuxi\xE8me ligne
+a              &\TeX   &1 2 3 4 5 6\cr % troisi\xE8me ligne
+\crcr}
+****************** Fin code ******************
+
+
+****************** Code 246 ******************
+\def\cvtop#1{%
+	\vtop{% \vtop assure que l'on est en mode vertical
+		\substtocs\temp{#1}{,}{\cr}% dans \temp, remplacer les "," par "\cr"
+		\halign{%
+			\hfil##\hfil\cr% pr\xE9ambule : centrer le contenu
+			\temp\crcr}% mettre \temp dans l'alignement
+	}% \temp est d\xE9truite en sortant de la boite
+}
+
+texte avant...\cvtop{Ligne du haut,Tr\xE8s grande ligne du milieu,Ligne du bas pour finir}%
+...texte apr\xE8s
+****************** Fin code ******************
+
+
+****************** Code 247 ******************
+\def\calcmaxdim#1#2{%
+	\setbox0=\vtop{% \vtop assure que l'on est en mode vertical (interne)
+		\substtocs\temp{#2}{,}{\cr}% dans \temp, remplacer les "," par "\cr"
+		\halign{##\hfil\cr% pr\xE9ambule : composer au fer \xE0 gauche
+			\temp\crcr}% mettre \temp dans l'alignement
+	}% \temp est d\xE9truite en sortant de la boite
+	\edef#1{\the\wd0 }%
+}
+a) La plus grande longueur vaut
+   \calcmaxdim\foo{Ligne du haut,Tr\xE8s grande ligne du milieu,Ligne du bas pour finir}\foo
+
+b) V\xE9rification : \setbox0=\hbox{Tr\xE8s grande ligne du milieu}\the\wd0 
+****************** Fin code ******************
+
+
+****************** Code 248 ******************
+a) .......\vbox{\hrule\hbox{foo}\hbox{ligne du bas}\hrule}.......\medbreak
+b) .......\vrule\vtop{\hbox{foo}\hbox{ligne du bas}}\vrule.......
+****************** Fin code ******************
+
+
+****************** Code 249 ******************
+Une r\xE9glure de 1.5cm :\hrule width1.5cm
+foo\vrule width 2pt height .5cm depth .2cm bar
+****************** Fin code ******************
+
+
+****************** Code 250 ******************
+\def\showdim#1{%
+	\vrule width 0.4pt height 1ex  depth 0pt % trait vertical gauche
+	\vrule width #1    height0.4pt depth 0pt % r\xE9glure horizontale de longueur #1
+	\vrule width 0.4pt height 1ex  depth 0pt % trait vertical droit
+	\relax% stoppe la lecture de la pr\xE9c\xE9dente dimension
+}
+
+a) une longueur de 1 cm : \showdim{1cm}\par
+b) une longueur de 137,4 pt : \showdim{137,4pt}\par
+c) une longueur de 2 mm : \showdim{2mm}
+****************** Fin code ******************
+
+
+****************** Code 251 ******************
+
+\frboxsep=5pt \frboxrule=1pt 
+\leavevmode
+...%
+\vbox{%
+	\hrule height\frboxrule% r\xE9glure sup\xE9rieure
+	\kern\frboxsep% espace verticale haute
+	\hbox{\kern\frboxsep Programmation\kern\frboxsep}% contenu + espaces horizontales
+	\kern\frboxsep% espace verticale basse
+	\hrule height\frboxrule% r\xE9glure inf\xE9rieure
+	}%
+...
+****************** Fin code ******************
+
+
+****************** Code 252 ******************
+
+\frboxsep=5pt \frboxrule=0.6pt
+\def\FRbox#1{% /!\ ne change pas le mode H ou V en cours
+	\hbox{% mettre \xE0 la suite horizontalement les 3 choses suivantes :
+		\vrule width\frboxrule% 1) r\xE9glure gauche
+		\vbox{%                 2) un empilement vertical comprenant
+			\hrule height\frboxrule% a) r\xE9glure sup\xE9rieure
+			\kern\frboxsep%          b) espace verticale haute
+			\hbox{%                  c) contenu + espaces en mode H
+				\kern\frboxsep#1\kern\frboxsep
+			}%
+			\kern\frboxsep%          d) espace verticale basse
+			\hrule height\frboxrule% e)r\xE9glure inf\xE9rieure
+			}%
+		\vrule width\frboxrule% 3) r\xE9glure droite
+	}%
+}
+Ligne de base : ...\FRbox{Programmation}...%
+\frboxrule=2pt \FRbox{Programmation}...%
+\frboxsep=0pt \FRbox{Programmation}...%
+\frboxrule0.4pt \FRbox{Programmation}...
+****************** Fin code ******************
+
+
+****************** Code 253 ******************
+Persuadez-vous que :
+\vtop{
+	\vbox{
+		\hbox{Programmer}
+		\hbox{en}
+		\hbox{\TeX}
+		\hbox{est}% <- ligne de base de la \vtop
+	}
+	\hbox{\it tout sauf}
+	\hbox{facile.}
+}
+****************** Fin code ******************
+
+
+****************** Code 254 ******************
+%\newdimen\frboxrule \newdimen\frboxsep
+\frboxrule=0.4pt \frboxsep=2pt
+\def\frbox#1{% ne pas changer le mode H ou V en cours
+	\hbox{% enferme dans une \hbox
+		\vrule width\frboxrule% r\xE9glure gauche
+		\vtop{%
+			\vbox{% 1er \xE9l\xE9ment de la \vtop
+				\hrule height\frboxrule% r\xE9glure sup\xE9rieure
+				\kern\frboxsep% espace haut
+				\hbox{%
+					\kern\frboxsep% espace gauche
+					#1% contenu
+					\kern\frboxsep% espace droite
+					}%
+			}% puis autres \xE9l\xE9ments de la \vtop, sous la ligne de base
+			\kern\frboxsep% espace bas
+			\hrule height\frboxrule% r\xE9glure inf\xE9rieure
+		}%
+		\vrule width\frboxrule% r\xE9glure droite
+	}%
+}
+Ligne de base : ......\frbox{Programmation}......%
+\frboxrule=2pt \frbox{Programmation}......%
+\frboxsep=0pt \frbox{Programmation}......%
+\frboxrule0.4pt \frbox{Programmation}......
+****************** Fin code ******************
+
+
+****************** Code 255 ******************
+\def\centretitre#1{%
+	\medbreak% passe en mode v puis saute une espace verticale
+	\noindent% pas d'indentation et passe en mode horizontal
+	\frbox{% encadre
+		\vbox{% une boite verticale
+			\hsize=\dimexpr\hsize-2\frboxrule-2\frboxsep\relax
+			\parindent=0pt % pas d'indentation
+			\leftskip=0pt plus1fil \rightskip=\leftskip% ressorts de centrage
+			\parfillskip=0pt % annule le ressort de fin de paragraphe
+			#1% ins\xE8re le titre
+			\endgraf% et le compose
+			}%
+	}%
+	\medbreak% passe en mode v puis saute une espace verticale
+	\ignorespaces% mange les espaces situ\xE9s apr\xE8s la macro \centretitre
+}
+\frboxrule=0.8pt \frboxsep=5pt
+Voici un
+\centretitre{Titre}
+puis un
+\centretitre{Texte tr\xE8s long pour composer un titre qui va prendre plusieurs
+lignes et pour s'assurer que la composition s'effectue correctement}
+****************** Fin code ******************
+
+
+****************** Code 256 ******************
+Une r\xE9glure en hauteur : \vrule width 1cm height 10.4pt depth -10pt 
+****************** Fin code ******************
+
+
+****************** Code 257 ******************
+Une r\xE9glure en dessous: \vrule width 1cm depth 2.4pt height -2pt 
+****************** Fin code ******************
+
+
+****************** Code 258 ******************
+\def\souligne#1{%
+	\setbox0=\hbox{#1}% stocke le contenu dans le registre no 0
+	\setbox0=\hbox{% puis, dans une \hbox, construit une r\xE9glure
+		\vrule width\wd0 % de la longueur du contenu
+			depth\dimexpr\dp0 + 1.4pt\relax % dp = profondeur texte + 1.4pt
+			height\dimexpr-\dp0 - 1pt\relax % ht = -profondeux texte - 1pt
+	}%
+	\wd0=0pt \dp0=0pt \ht0=0pt % annule toutes les dimensions
+	\leavevmode \box0 % affiche la r\xE9glure
+	#1% puis le contenu
+}
+Voici \souligne{du texte normal}.\par
+Voici \souligne{du texte profond}.
+****************** Fin code ******************
+
+
+****************** Code 259 ******************
+\def\Souligne#1{%
+	\setbox0=\hbox{#1}%
+	\setbox0=\hbox{\vrule width\wd0 depth1.4pt height-1pt }%
+	\wd0=0pt \dp0=0pt \ht0=0pt 
+	\leavevmode \box0 #1%
+}
+Voici \Souligne{du texte normal}.\par
+Voici \Souligne{du texte profond}.
+****************** Fin code ******************
+
+
+****************** Code 260 ******************
+\def\Souligne#1{%
+	\setbox0=\hbox{#1}%
+	\lower 1pt % abaisser \xE0 1pt sous la ligne de base
+		\rlap{% une \hbox en surimpression vers la droite
+			\vrule width\wd0 height0pt depth0.4pt % contenant le soulignement
+		}%
+	#1% puis afficher le <texte>
+}
+Voici \Souligne{du texte normal}.\par
+Voici \Souligne{du texte profond}.
+****************** Fin code ******************
+
+
+****************** Code 261 ******************
+\newdimen\stackwd \stackwd=3em % dimension horizontale interne des cadres
+\catcode`@11
+\def\stackbox#1{%
+	\par% termine le paragraphe en cours
+	\noindent
+	\stackbox at i#1\\\quark\\% ajoute "\\\quark\\" \xE0 la fin et appelle \stackbox at i
+	\par
+}
+
+\def\stackbox at i#1\\{% #1=ligne courante
+	\def\temp@{#1}% stocke la ligne courante
+	\unless\ifx\quark\temp@% si ce n'est pas la fin
+		\hfill % ressort infini de centrage (et fait passer en mode horizontal)
+		\noindent
+		\doforeach\current at item\in{#1}% pour chaque \xE9l\xE9ment dans la ligne courante...
+			{\frbox{% ...encadrer
+				\hbox to\stackwd{% une \hbox de largeur \stackwd
+					\hss% ressort de centrage
+					\current at item% l'\xE9l\xE9ment courant
+					\hss% ressort de centrage
+					}
+				}% fin de la \frbox
+			}% fin \doforeach
+		\hfill% ressort infini de centrage
+		\null% assure que le dernier ressort est pris en compte
+		\par% finir le paragraphe
+		\nobreak% interdire une coupure de page
+		\nointerlineskip% ne pas ins\xE9rer le ressort d'interligne
+		\expandafter\stackbox at i% et recommencer
+	\fi
+}
+\catcode`@12
+
+\frboxrule=0.5pt \frboxsep=3pt 
+\stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}
+****************** Fin code ******************
+
+
+****************** Code 262 ******************
+a\vrule width0.2pt height15pt depth0pt \quad
+a\vrule width0.2pt height0pt depth5pt \quad
+a\vrule width0.2pt height10pt depth10pt \quad
+a\vrule width1cm height0.2pt depth0pt
+****************** Fin code ******************
+
+
+****************** Code 263 ******************
+\frboxsep0pt %encadrement au plus proche
+\leavevmode
+\frbox{a\vrule width0pt height15pt depth0pt }\quad
+\frbox{a\vrule width0pt height0pt depth5pt }\quad
+\frbox{a\vrule width0pt height10pt depth10pt }\quad
+\frbox{a\vrule width1cm height0pt depth0pt }
+****************** Fin code ******************
+
+
+****************** Code 264 ******************
+\def\rectangle#1#2{%
+	\begingroup% dans un groupe
+		\frboxsep = 0pt % encadrer au plus proche
+		\frboxrule= 0.4pt % en traits assez fins
+		\frbox{%
+			\vrule width#1 height0pt depth0pt %strut horizontal
+			\vrule width0pt height#2 depth0pt %strut vertical
+		}%
+	\endgroup% fermer le groupe
+}
+Carr\xE9 de 0.5 cm : \rectangle{0.5cm}{0.5cm}\smallskip
+
+Rectangle de 2.5cm par 3pt : \rectangle{2.5cm}{3pt}
+****************** Fin code ******************
+
+
+****************** Code 265 ******************
+\newdimen\stackwd \stackwd=3em 
+\catcode`\@11
+\def\stackbox#1{%
+	\par% termine le paragraphe en cours
+	\begingroup% dans un groupe semi-simple
+		\parindent=0pt% pas d'indentation
+		\parskip=0pt% annuler le \parskip
+		\setbox0\hbox{\xC0gjp}% boite pour le strut
+		\edef\stack at strut{\vrule width\z@ height\the\ht0 depth\the\dp0 }% d\xE9finit le strut
+		\stackbox at i#1\\\quark\\% ajoute "\\\quark\\" \xE0 la fin et appelle \stackbox at i
+		\unkern% annule la derni\xE8re compensation verticale
+		\par
+	\endgroup
+}
+\def\stackbox at i#1\\{% #1=ligne courante
+	\def\temp@{#1}% stocke la ligne courante
+	\unless\ifx\quark\temp@% si ce n'est pas la fin
+		\hfill % ressort infini de centrage (passe en mode horizontal)
+		\doforeach\current at item\in{#1}% pour chaque \xE9l\xE9ment dans la ligne courante...
+			{\frbox{% ...encadrer
+				\hbox to\stackwd{% une \hbox de largeur \stackwd contenant
+					\hss%         1) ressort de centrage
+					\stack at strut% 2) strut de dimension verticale
+					\current at item%3) l'\xE9lement courant
+					\hss}%        4)ressort de centrage
+				}% fin de la \fbox
+			\kern-\frboxrule% revenir en arri\xE8re pour superposer les r\xE9glures verticales
+			}% fin de \doforeach
+		\unkern% annuler la derni\xE8re compensation horizontale
+		\hfill% ressort infini de centrage
+		\null% fait prendre en compte le dernier ressort
+		\par% termine le paragraphe
+		\nobreak% interdit une coupure de page
+		\nointerlineskip% sinon, ne pas ajouter le ressort d'interligne
+		\kern-\frboxrule% superposer les r\xE9glures horizontales
+		\expandafter\stackbox at i% et recommencer
+	\fi
+}
+\frboxrule=0.5pt 
+\frboxsep=3pt 
+\stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}
+****************** Fin code ******************
+
+
+****************** Code 266 ******************
+\catcode`\@11
+\def\lineboxed#1{%
+	\par% termine le paragraphe en cours
+	\begingroup% dans un groupe semi-simple
+		\parindent=0pt% pas d'indentation
+		\parskip=0pt% annuler le \parskip
+		\setbox0\hbox{\xC0gjp}% boite pour le strut
+		\edef\stack at strut{\vrule width\z@ height\the\ht0 depth\the\dp0 }% d\xE9finit le strut
+		\lineboxed at i#1\\\quark\\% ajoute "\\\quark\\" \xE0 la fin et appelle la macro r\xE9cursive
+		\unkern% annule la derni\xE8re compensation verticale
+		\par
+	\endgroup
+}
+\def\lineboxed at i#1\\{% #1=ligne courante
+	\def\temp@{#1}% stocke la ligne courante
+	\unless\ifx\quark\temp@% si ce n'est pas la fin
+		\cnttimestocs{#1,}{,}\nb at args% re\xE7oit le nombre d'arguments dans la ligne courante
+		\edef\dim at box{\the\dimexpr(\hsize-\frboxrule*(\nb at args+1)-
+		              \frboxsep*2*\nb at args)/\nb at args}%
+		\hbox{%
+			\doforeach\current at item\in{#1}% pour chaque \xE9l\xE9ment dans la ligne courante...
+				{\frbox{% ...encadrer
+					\hbox to\dim at box{% une \hbox de largeur \dim at box contenant
+						\hss%         1) ressort de centrage
+						\stack at strut% 2) strut de dimension verticale
+						\current at item%3) l'\xE9lement courant
+						\hss}%        4)ressort de centrage
+					}% fin de la \fbox
+				\kern-\frboxrule% revenir en arri\xE8re pour superposer les r\xE9glures verticales
+				}% fin de \doforeach
+			\unkern% annuler la derni\xE8re compensation horizontale
+		}%
+		\par% termine le paragraphe
+		\nobreak% interdit une coupure de page
+		\nointerlineskip% sinon, ne pas ajouter le ressort d'interligne
+		\kern-\frboxrule% superposer les r\xE9glures horizontales
+		\expandafter\lineboxed at i% et recommencer
+	\fi
+}
+\catcode`\@12
+\lineboxed{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}\medbreak
+
+\frboxrule=1.5pt 
+\frboxsep=3pt 
+\lineboxed{,,,,,,,\\,,\\,,,,,,}
+****************** Fin code ******************
+
+
+****************** Code 267 ******************
+\xunit=0.5cm \yunit=0.5cm \mainrule=0.8pt \subrule=0.2pt
+\def\vlap#1{\vbox to0pt{\vss#1\vss}}
+\catcode`@11
+\def\grid#1#2#3#4{%
+	\vbox{% empiler les \xE9l\xE9ments verticalement
+		\offinterlineskip% pas de ressort d'interligne
+		\edef\total at wd{\the\dimexpr\xunit*#1\relax}% largeur totale ds r\xE9glures
+		\for\ii = 1 to #3 \do1% pour chaque carreau vertical (\ii=variable muette)
+			{\vlap{\hrule width\total at wd height\mainrule}% tracer la r\xE9glure horizontale
+			\kern\yunit% ins\xE9rer l'espace vertical
+			}%
+		\vlap{\hrule width\total at wd height\mainrule}% derni\xE8re r\xE9glure horizontale
+	}%
+}
+\catcode`@12
+\setbox0\hbox{\grid{4}{}{3}{}}% range la quadrillage dans le registre no 0
+Essai \copy0{} qui a pour
+largeur=\convertunit{\wd0}{cm} cm et pour hauteur=\convertunit{\ht0}{cm} cm
+****************** Fin code ******************
+
+
+****************** Code 268 ******************
+D\xE9but\vbox to0pt{\hbox{sous}\hbox{la ligne de base}\vss}suite
+****************** Fin code ******************
+
+
+****************** Code 269 ******************
+\xunit=0.5cm \yunit=0.5cm \mainrule=0.8pt \subrule=0.2pt
+\def\vlap#1{\vbox to0pt{\vss#1\vss}}
+\catcode`@11
+\def\grid#1#2#3#4{%
+	\vbox{% empiler les \xE9l\xE9ments verticalement
+		\offinterlineskip% pas de ressort d'interligne
+		\edef\total at wd{\the\dimexpr\xunit*#1\relax}% largeur totale de la boite
+		\edef\sub at unit{\the\dimexpr\yunit/#4\relax}% hauteur verticale de la subdivision
+		\for\ii = 1 to #3 \do% pour chaque unit\xE9 verticale en partant du haut, tracer :
+			{\vlap{\hrule width\total at wd height\mainrule}% la r\xE9glure horizontale principale
+			% et dessous, les r\xE9glures horizontales secondaires :
+			\vbox to\z@{% dans une \vbox de hauteur nulle,
+				\for\jj = 2 to #4 \do 1% ins\xE9rer #4-1 fois sous la position courante :
+					{\kern\sub at unit % l'espace verticale
+					\vlap{\hrule width\total at wd height\subrule}% et la r\xE9glure secondaire
+					}%
+				\vss% ressort qui se comprime pour satisfaire la hauteur nulle
+			}%
+			\kern\yunit% ins\xE9rer l'espace vertical entre r\xE9glures principales
+			}%
+		\vlap{\hrule width\total at wd height\mainrule}% derni\xE8re r\xE9glure principale du bas
+	}%
+}
+\catcode`@12
+\setbox0=\hbox{\grid{4}{}{3}{5}}
+Essai \copy0{} qui a pour
+largeur=\convertunit{\wd0}{cm} cm et pour hauteur=\convertunit{\ht0}{cm} cm
+****************** Fin code ******************
+
+
+****************** Code 270 ******************
+\mainrule=0.8pt \subrule=0.2pt
+\def\vlap#1{\vbox to0pt{\vss#1\vss}}
+\catcode`@11
+\def\grid#1#2#3#4{%
+	\vbox{% empiler les \xE9l\xE9ments verticalement
+		\offinterlineskip% pas de ressort d'interligne
+		% #################### Trac\xE9 des r\xE9glures verticales ####################
+		\vbox to\z@{% dans une \vbox de hauteur nulle
+			\edef\total at ht{\the\dimexpr\yunit*#3\relax}% hauteur totale
+			\edef\sub at unit{\the\dimexpr\xunit/#2\relax}% espace entre 2 subdivisions
+			\rlap{% mettre \xE0 droite de la position sans bouger
+				\for\ii = 1 to #1 \do 1% pour chaque unit\xE9 horizontale
+					{\clap{\vrule width\dimexpr\mainrule height\total at ht}% r\xE9glure principale
+					\rlap{% mettre \xE0 droite de la position sans bouger
+						\for\jj = 2 to #2 \do 1% ins\xE9rer #2-1 fois
+							{\kern\sub at unit % l'espace horizontal
+							\clap{\vrule width\subrule height\total at ht}% et la r\xE9glure verticale
+							}%
+					}%
+					\kern\xunit % ins\xE9rer l'espace entre r\xE9glures horizontales
+					}%
+				\clap{\vrule width\mainrule height\total at ht}% derni\xE8re r\xE9glure principale
+			}%
+			\vss% compense la hauteur=0pt de la \vbox
+		}%
+		% #################### Trac\xE9 des r\xE9glures horizontales ####################
+		\edef\total at wd{\the\dimexpr\xunit*#1\relax}% largeur totale de la boite
+		\edef\sub at unit{\the\dimexpr\yunit/#4\relax}% espace entre 2 subdivisions
+		\for\ii = 1 to #3 \do 1% pour chaque carreau vertical en partant du haut :
+			{\vlap{\hrule width\total at wd height\mainrule}% r\xE9glure horizontale principale
+			% et dessous, les r\xE9glures secondaires :
+			\vbox to\z@{% dans une \vbox de hauteur nulle,
+				\for\jj = 2 to #4 \do 1% ins\xE9rer #4-1 fois sous la position courante :
+					{\kern\sub at unit % l'espace vertical
+					\vlap{\hrule width\total at wd height\subrule}% et la r\xE9glure secondaire
+					}%
+				\vss% ressort qui se comprime pour satisfaire la hauteur nulle
+			}%
+			\kern\yunit% ins\xE9rer l'espace vertical entre r\xE9glures principales
+			}%
+		\vlap{\hrule width\total at wd height\mainrule}% derni\xE8re r\xE9glure horizontale
+	}%
+}
+\catcode`@12
+Grille 1 : \xunit=1cm \yunit=1cm \grid{5}{10}{2}{10}\smallskip
+
+Grille 2 : \xunit=0.5cm \yunit=0.5cm \grid{7}{1}{3}{1}\smallskip
+
+Grille 3 : \xunit=1.5cm \yunit=0.5cm \grid{4}{3}{3}{2}
+****************** Fin code ******************
+
+
+****************** Code 271 ******************
+\vrule\hbox to10cm{\leaders\hbox to1.5cm{\hss A\hss}\hfill}\vrule
+****************** Fin code ******************
+
+
+****************** Code 272 ******************
+\frboxsep=-\frboxrule \def~{\leavevmode\raise.75ex\hbox{\vrule height.2pt width1em}}
+~\hbox to10cm{\leaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~
+
+~\hbox to10cm{\cleaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~
+
+~\hbox to10cm{\xleaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~
+****************** Fin code ******************
+
+
+****************** Code 273 ******************
+a) \leavevmode\hbox to10cm{\leaders\hrule\hfill}\smallskip
+
+b) \hbox to10cm{\leaders\hbox{\vrule height0.2pt width2.5mm \kern1.5mm}\hfill}
+
+c) \vrule width0.2pt height1ex depth0pt % premi\xE8re r\xE9glure verticale
+     \hbox to10cm{% puis r\xE9p\xE9tition de "_|"
+     \leaders\hbox{\vrule width2em height0.2pt \vrule width0.2pt height1ex}\hfill}
+
+d) \hbox to10cm{\leaders\hbox{%
+		\vrule height.2pt width.5em% 1/2 palier bas
+		\vrule height5pt width0.2pt% mont\xE9e au palier haut
+		\vrule height5pt depth-4.8pt width1em% palier haut
+		\vrule height5pt width0.2pt% descente au palier bas
+		\vrule height.2pt width.5em% 1/2 palier bas
+		}\hfill}
+****************** Fin code ******************
+
+
+****************** Code 274 ******************
+\mainrule=0.8pt \subrule=0.2pt
+\def\carreau#1#2{% #1=nb subdiv H  #2=nb subdiv V
+	\vbox to\yunit{% dans un \vbox de hauteur \yunit
+		\offinterlineskip% pas de ressort d'interligne
+		\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale du haut
+		\leaders% r\xE9p\xE9ter (ici ce sera donc #2-1 fois)
+			\vbox to\dimexpr\yunit/#2\relax% une \vbox de hauteur \yunit/#2
+				{\vss% ressort qui va s'\xE9tirer \xE0 \yunit/#2
+				\vlap{\hrule height\subrule width\xunit}% r\xE9glure de subdiv de dim 0pt
+				}\vfill
+		\kern\dimexpr\yunit/#2\relax% derni\xE8re espace verticale
+		\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale du bas
+	}%
+}
+\yunit=1cm
+\leavevmode \carreau{}{4} puis \carreau{}{10}
+****************** Fin code ******************
+
+
+****************** Code 275 ******************
+\mainrule=0.8pt \subrule=0.2pt
+\def\carreau#1#2{% #1=nb subdiv H  #2=nb subdiv V
+	% ######## r\xE9glures horizontales ########
+	\rlap{% mettre \xE0 droite de la position sans bouger
+		\vbox to\yunit{% dans un \vbox de hauteur \yunit
+			\offinterlineskip% pas de ressort d'interligne
+			\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale du haut
+			\leaders% r\xE9p\xE9ter (ici ce sera #2-1 fois)
+				\vbox to\dimexpr\yunit/#2\relax% une \vbox de hauteur \yunit/#2
+					{\vss% ressort qui va s'\xE9tirer \xE0 \yunit/#2
+					\vlap{\hrule height\subrule width\xunit}% r\xE9glure de subdiv de dim 0pt
+					}\vfill% ressort de \leaders
+			\kern\dimexpr\yunit/#2\relax% derniere espace verticale
+			\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale du bas
+		}%
+	}%
+	% ######## r\xE9glures verticales ########
+	\hbox to\xunit{% dans une \hbox de longueur \xunit
+		\clap{\vrule height\yunit width\mainrule}% r\xE9glure principale de gauche
+		\leaders% r\xE9p\xE9ter (ici ce sera #1-1 fois)
+			\hbox to\dimexpr\xunit/#1\relax
+				{\hss% ressort qui va s'\xE9tirer \xE0 \xunit/#1
+				\clap{\vrule height\yunit width\subrule}% r\xE9glure H de dimension 0
+				}\hfill% ressort de \leaders
+			\kern\dimexpr\xunit/#1\relax% derni\xE8re espace H
+			\clap{\vrule height\yunit width\mainrule}% r\xE9glure principale de droite
+	}%
+}
+\yunit=1cm \xunit=2cm
+\leavevmode \carreau{3}{4} puis \carreau{8}{10}
+****************** Fin code ******************
+
+
+****************** Code 276 ******************
+\mainrule=0.8pt \subrule=0.2pt
+\def\grid#1#2#3#4{%
+	\vbox to#3\yunit{% dans une boite verticale de hauteur #3*\yunit
+		\leaders% r\xE9p\xE9ter verticalement
+			\hbox to#1\xunit{% une boite de longueur #1*\xunit
+				\leaders% dans laquelle se r\xE9p\xE8te horizontalement
+					\hbox{\carreau{#2}{#4}}% le carreau de largeur \xunit
+				\hfill}%
+		\vfill
+	}%
+}
+Grille 1 : \xunit=1cm \yunit=1cm \grid{5}{10}{2}{10}\smallskip
+
+Grille 2 : \xunit=0.5cm \yunit=0.5cm \grid{7}{1}{3}{1}\smallskip
+
+Grille 3 : \xunit=1.5cm \yunit=0.5cm \grid{4}{3}{3}{2}
+****************** Fin code ******************
+
+
+****************** Code 277 ******************
+\outer\def\foo{Bonjour}
+\def\bar{\foo}
+****************** Fin code ******************
+
+
+****************** Code 278 ******************
+\outer\def\foo{Bonjour}
+\expandafter\def\expandafter\bar\expandafter{\noexpand\foo}
+\meaning\bar
+
+\edef\baz{\noexpand\foo}
+\meaning\baz
+****************** Fin code ******************
+
+
+****************** Code 279 ******************
+\catcode`\@11
+\long\def\filedef#1#2{%
+	\begingroup
+		\let\input\@@input% <- utilisateurs de latex uniquement
+		\everyeof{\eof at nil\noexpand}% ins\xE8re "\eof at nil\noexpand" \xE0 la fin du fichier
+		\expandafter\filedef at i\expandafter#1% d\xE9veloppe \input #2
+			\expandafter\relax\input #2
+}
+\long\def\filedef at i#1#2\eof at nil{%
+	\endgroup
+	\expandafter\def\expandafter#1\expandafter{\gobone#2}% mange le \relax
+}
+\catcode`\@12
+\filedef\foo{test.txt}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 280 ******************
+% canal de lecture employ\xE9 dans tout ce chapitre
+\def\iffileexists#1#2{% #1=canal de lecture  #2=nom du fichier
+	\openin#1=#2
+	\ifeof#1% le fichier n'existe pas
+		\closein#1
+		\expandafter\secondoftwo% renvoyer faux
+	\else
+		\closein#1
+		\expandafter\firstoftwo% sinon renvoyer vrai
+	\fi
+}
+a) \iffileexists\rtest{test.txt}{vrai}{faux}\qquad
+b) \iffileexists\rtest{foobar.txt}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 281 ******************
+\openin\rtest =filetest.txt
+\read\rtest to \foo% lit la premi\xE8re ligne
+1) Signification : \meaning\foo.\par% signification de ce qui a \xE9t\xE9 lu
+1) Ex\xE9cution : \foo\par
+\read\rtest to \foo% lit la deuxi\xE8me ligne
+2) Signification : \meaning\foo.\par
+2) Ex\xE9cution : \foo\par
+\read\rtest to \foo% lit la derni\xE8re ligne
+3) Signification : \meaning\foo.\par
+3) Ex\xE9cution : \foo
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 282 ******************
+\openin\rtest =filetest.txt
+\readline\rtest to \foo% lit la premi\xE8re ligne
+1) Signification : \meaning\foo.\par% signification de ce qui a \xE9t\xE9 lu
+1) Ex\xE9cution : \foo\par
+\readline\rtest to \foo% lit la deuxi\xE8me ligne
+2) Signification : \meaning\foo.\par
+2) Ex\xE9cution : \foo\par
+\readline\rtest to \foo% lit la derni\xE8re ligne
+3) Signification : \meaning\foo.\par
+3) Ex\xE9cution : \foo
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 283 ******************
+Valeur de \string\endlinechar = \number\endlinechar\par
+Caract\xE8re correspondant : << \char\endlinechar{} >>
+****************** Fin code ******************
+
+
+****************** Code 284 ******************
+\openin\rtest =filetest.txt
+Ligne 1 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la premi\xE8re ligne
+\meaning\foo.\par% donne ce qui a \xE9t\xE9 lu
+Ligne 2 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la deuxi\xE8me ligne
+\meaning\foo.\par
+Ligne 3 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la derni\xE8re ligne
+\meaning\foo.
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 285 ******************
+\def\xread#1to#2{%
+	\ifcs{#2}% si #2 est une s\xE9quence de contr\xF4le
+		{\edef\restoreendlinechar{\endlinechar=\the\endlinechar}%
+		\endlinechar=-1 % supprime le caract\xE8re mis en fin de ligne
+		\read#1to#2% lit la ligne et l'assigne \xE0 la macro #2
+		\restoreendlinechar\relax% restaure le \endlinechar
+		}% si #2 n'est pas une s\xE9quence de contr\xF4le,
+		{\xread#1to}% ignorer #2, et recommencer
+}
+
+\openin\rtest =filetest.txt
+Ligne 1 : \xread\rtest to \foo% lit la premi\xE8re ligne
+\meaning\foo.\par% donne ce qui a \xE9t\xE9 lu
+Ligne 2 : \xread\rtest to \foo% lit la deuxi\xE8me ligne
+\meaning\foo.\par
+Ligne 3 : \xread\rtest to \foo% lit la derni\xE8re ligne
+\meaning\foo.
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 286 ******************
+\def\xread{% doit \xEAtre suivie de "<nombre> to \<macro>"
+	\edef\restoreendlinechar{\endlinechar=\the\endlinechar}%
+	\endlinechar=-1 % neutralise \endlinechar
+	\afterassignment\restoreendlinechar% apr\xE8s l'assignation, restaurer \endlinechar
+	\read% attend <nombre> to \<macro> pour effectuer l'assignation
+}
+\catcode`\@12
+
+\openin\rtest =filetest.txt
+Ligne 1 : \xread\rtest to \foo% lit la premi\xE8re ligne
+\meaning\foo.\par% donne ce qui a \xE9t\xE9 lu
+Ligne 2 : \xread\rtest to \foo% lit la deuxi\xE8me ligne
+\meaning\foo.\par
+Ligne 3 : \xread\rtest to \foo% lit la derni\xE8re ligne
+\meaning\foo.
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 287 ******************
+\def\macroname{% se d\xE9veloppe en le nom de la macro qui suit sans 
+               % le caract\xE8re d'\xE9chappement
+	\ifnum\escapechar>-1 % si le caract\xE8re d'\xE9chappement est positif
+		\ifnum\escapechar<256 % et inf\xE9rieur \xE0 256, d\xE9velopper les 2 "\fi"
+			\expandafter\expandafter\expandafter\expandafter% et le "\string", puis
+			\expandafter\expandafter\expandafter\gobone% manger le "\" avec \gobone
+		\fi
+	\fi
+	\string% doit \xEAtre suivi d'une macro
+}
+\catcode`\@11
+\newcount\field at cnt
+\def\searchitem#1#2#3#4{% #1= canal  #2=nom fichier #3=r\xE9f\xE9rence  #4=macro \xE0 d\xE9finir
+	\let#4\gobone% pour l'instant, #4=\gobone
+	\openin#1=#2\relax
+	\unless\ifeof#1% si le fichier existe
+		\lowercase{\def\sought at firstfield{#3}}% stocke le 1er champ \xE0 chercher
+		\edef\macro at name{\macroname#4}% nom de la macro sans "\"
+		\xread#1 to \current at line% lire la premi\xE8re ligne
+		\field at cnt=0 % initialiser le compteur de champs
+		% ################ sauvegarde du nom des champs ################
+		\expsecond{\doforeach\current at field\in}\current at line% pour chaque champ
+			{\advance\field at cnt1 % incr\xE9menter le compteur de champs
+			\lowercase\expandafter{% e texte de remplacement de \current at field en minuscule
+				\expandafter\def\expandafter\current at field\expandafter{\current at field}%
+			}%
+			% sauvegarder chaque champ de la 1re ligne (qui sont les intitul\xE9s) dans une macro
+			\letname{fieldname\number\field at cnt}=\current at field
+			}%
+		\edef\field at num{\number\field at cnt}% nombre de champs
+		% ################ lecture des lignes de donn\xE9es ################
+		\loop% tant que...
+			\unless\ifeof#1\relax% ...la fin du fichier n'est pas atteinte
+				\xread#1 to \current at line% lire une ligne
+				\unless\ifx\current at line\empty% si elle n'est pas vide
+					% examniner les champs qu'elle contient (aller \xE0 \test at field)
+					\expsecond{\expandafter\test at field\current at line\@nil}\macro at name%
+				\fi
+		\repeat
+	\fi
+	\closein#1\relax
+}
+
+\def\test at field#1,#2\@nil#3{% #1=champ no 1 #2=autres champs #3=nom de la macro sans "\"
+	\def\current at firstfield{#1}% stocke le premier champ de la ligne en cours
+	\ifx\current at firstfield\sought at firstfield% s'il est \xE9gal \xE0 celui cherch\xE9
+		\defname{#3.\csname fieldname1\endcsname}{#1}% d\xE9finir la macros \<#3."champ 1">
+		\field at cnt=1 % initialiser le compteur de champ
+		\doforeach\current at field\in{#2}% puis, pour i>2, d\xE9finir les macros \<#3."champ i">
+			{\advance\field at cnt1 % incr\xE9menter le compteur de champ
+			\letname{#3.\csname fieldname\number\field at cnt\endcsname}=\current at field
+			}%
+		\defname{#3}##1{% et d\xE9finir la macro \<#3>
+			\ifcsname#3.##1\endcsname% si la macro \<#3."argument"> existe d\xE9j\xE0
+				\csname#3.##1\expandafter\endcsname% l'ex\xE9cuter apr\xE8s avoir mang\xE9 le \fi
+			\fi
+		}%
+	\fi
+}
+\catcode`\@12
+
+\searchitem\rtest{fournitures.txt}{4562u}\monarticle
+r\xE9f = \monarticle{ref},
+d\xE9nomination = \monarticle{item},
+prix = \monarticle{prix},
+fournisseur = \monarticle{fournisseur},
+champ non existant = \monarticle{foobar}.
+
+\searchitem\rtest{fournitures.txt}{truc}\essai% r\xE9f\xE9rence "truc" n'existe pas
+r\xE9f = \essai{ref},
+d\xE9nomination = \essai{item},
+prix = \essai{prix},
+fournisseur = \essai{fournisseur}.
+****************** Fin code ******************
+
+
+****************** Code 288 ******************
+\def\macroname{% se d\xE9veloppe en le nom de la macro qui suit sans 
+               % le caract\xE8re d'\xE9chappement
+	\ifnum\escapechar>-1 % si le caract\xE8re d'\xE9chappement est positif
+		\ifnum\escapechar<256 % et inf\xE9rieur \xE0 256, d\xE9velopper les 2 "\fi"
+			\expandafter\expandafter\expandafter\expandafter% et le "\string", puis
+			\expandafter\expandafter\expandafter\gobone% manger le "\" avec \gobone
+		\fi
+	\fi
+	\string% doit \xEAtre suivi d'une macro
+}
+\catcode`\@11
+\newcount\field at cnt
+\newif\ifsearch at repeat
+\def\assign at arg#1=#2\@nil{%
+	\def\sought at fieldnumber{#1}% no du champ \xE0 chercher
+	\def\sought at fielvalue{#2}% et sa valeur
+}
+\def\searchitem#1#2#3#4{% #1= canal  #2=nom fichier #3=champ cherch\xE9  #4=macro \xE0 d\xE9finir
+	\let#4\gobone% pour l'instant, #4=\gobone
+	\openin#1=#2\relax%
+	\unless\ifeof#1% si le fichier existe
+		\edef\macro at name{\macroname#4}% nom de la macro sans "\"
+		\xread#1 to \current at line% lire et ignorer la premi\xE8re ligne
+		\ifin{#3}{=}% si #3 contient =
+			{\assign at arg#3\@nil}% trouver le no de champ et sa valeur
+			{\def\sought at fieldnumber{1}% sinon, no du champ = 1
+			\def\sought at fielvalue{#3}% et sa valeur = #3
+			}%
+		% ################ lecture des lignes de donn\xE9es ################
+		\search at repeattrue% poursuite de la boucle loop : vraie
+		\loop% tant que...
+			\ifeof#1\relax% ...la fin du fichier n'est pas atteinte
+				\search at repeatfalse% sortir de la boucle loop
+			\else
+				\xread#1 to \current at line% lire une ligne
+				\unless\ifx\current at line\empty% si elle n'est pas vide
+					% examniner les champs qu'elle contient (aller \xE0 \test at field)
+					\expsecond{\expandafter\test at field\current at line\@nil}\macro at name%
+				\fi
+			\fi
+			\ifsearch at repeat% ne poursuivre que si le bool\xE9en en vrai
+		\repeat
+	\fi
+	\closein#1\relax
+}
+
+\def\test at field#1\@nil#2{% #1=champs #2=nom de la macro sans "\"
+	\field at cnt=0 % initialiser le compteur de champ
+	\doforeach\current at field\in{#1}% parcourir les champs de la ligne en cours
+		{\advance\field at cnt1 % incr\xE9menter le compteur de champ
+		\ifnum\field at cnt=\sought at fieldnumber\relax% si c'est le bon num\xE9ro de champ
+			\ifx\current at field\sought at fielvalue% et si le champ correspond \xE0 celui cherch\xE9
+				\search at repeatfalse% sortir de la boucle loop
+				\doforeachexit% sortir de la boucle \doforeach en cours
+			\fi
+		\fi
+		}%
+	\unless\ifsearch at repeat% si la ligne a \xE9t\xE9 trouv\xE9e
+		\field at cnt=0 % initialiser le compteur de champ
+		\doforeach\current at field\in{#1}% parcourir \xE0 nouveau les champs de la ligne
+				{\advance\field at cnt1 % incr\xE9menter le compteur de champ
+				\letname{#2.\number\field at cnt}=\current at field% faire l'assignation
+				}%
+		\defname{#2}##1{% et d\xE9finir la macro \<#2>
+			\ifcsname#2.##1\endcsname% si la macro \<#2."argument"> existe d\xE9j\xE0
+				\csname#2.##1\expandafter\endcsname% l'ex\xE9cuter apr\xE8s avoir mang\xE9 le \fi
+			\fi
+		}%
+	\fi
+}
+\catcode`\@12
+a) \searchitem\rtest{basecourse.txt}{3=283}\foo
+   "\foo1", "\foo2", "\foo3", "\foo4", "\foo5", "\foo6", "\foo7"
+
+b) \searchitem\rtest{basecourse.txt}{Valet}\bar
+   "\bar1", "\bar2", "\bar3", "\bar4", "\bar5", "\bar6", "\bar{abcd}"
+****************** Fin code ******************
+
+
+****************** Code 289 ******************
+\def\showfilecontent#1#2{% #1=canal de lecture #2=nom de fichier
+	\begingroup
+		\tt% s\xE9lectionner la fonte \xE0 chasse fixe
+		\openin#1=#2\relax
+		\ifeof#1% si la fin du fichier est d\xE9j\xE0 atteinte, il n'existe pas et
+			Le fichier n'existe pas% afficher le message
+		\else% le fichier existe
+			\def\do##1{\catcode`##1=12 }%
+			\dospecials% neutraliser tous les tokens sp\xE9ciaux
+			\obeyspaces% rendre l'espace actif
+			\loop
+				\xread#1 to \currline% lire une ligne
+				\unless\ifeof#1% si la fin du fichier n'est pas atteinte
+				\leavevmode\par% aller \xE0 la ligne
+				\currline% afficher la ligne lue
+			\repeat% recommencer
+		\fi
+		\closein#1\relax
+	\endgroup
+}
+
+Contenu du fichier : "\showfilecontent\rtest{readtest.txt}", affich\xE9 tel quel
+****************** Fin code ******************
+
+
+****************** Code 290 ******************
+\def\showfilecontent#1#2{% #1=canal de lecture #2=nom de fichier
+	\begingroup
+		\tt% s\xE9lectionner la fonte \xE0 chasse fixe
+		\openin#1=#2\relax
+		\ifeof#1% si la fin du fichier est d\xE9j\xE0 atteinte, il n'existe pas et
+			Le fichier n'existe pas% afficher le message
+		\else% le fichier existe
+			\def\do##1{\catcode`##1=12 }%
+			\dospecials% neutraliser tous les tokens sp\xE9ciaux
+			\obeyspaces% rendre l'espace actif
+			\def\magicpar{\let\magicpar=\par}%
+			\loop
+				\xread#1 to \currline% lire une ligne
+				\unless\ifeof#1% si la fin du fichier n'est pas atteinte
+				\leavevmode\magicpar% former le paragraphe (sauf \xE0 la 1er it\xE9ration)
+				\currline% afficher la ligne
+			\repeat% recommencer
+		\fi
+		\closein#1\relax
+	\endgroup
+}
+
+Contenu du fichier : "\showfilecontent\rtest{readtest.txt}", affich\xE9 tel quel
+****************** Fin code ******************
+
+
+****************** Code 291 ******************
+% sera le canal d'\xE9criture dans tout ce chapitre
+\immediate\openout\wtest=writetest.txt % lie \wtest au fichier
+\immediate\write\wtest{Programmer en \noexpand\TeX{} est   facile.}% \xE9crit une ligne
+\immediate\write\wtest{Et utile...}% puis une autre
+\immediate\closeout\wtest% d\xE9fait la liaison
+a) Contenu du fichier :\par
+"\showfilecontent\rtest{writetest.txt}"% affiche le contenu du fichier
+\medbreak
+% 2e tentative :
+b) Contenu du fichier :\par
+\immediate\openout\wtest=writetest.txt % lie \wtest au fichier
+\immediate\write\wtest{Essai d'\xE9criture}% \xE9crit une ligne
+\immediate\closeout\wtest% d\xE9fait la liaison
+"\showfilecontent\rtest{writetest.txt}"% affiche le contenu du fichier
+****************** Fin code ******************
+
+
+****************** Code 292 ******************
+\def\noexpwrite#1#2{% #1=num\xE9ro de canal  #2=texte \xE0 \xE9crire
+	\write#1{\unexpanded{#2}}%
+}
+\immediate\openout\wtest=writetest.txt 
+\immediate\noexpwrite\wtest{Programmer en \TeX{} est   facile.}%
+\immediate\noexpwrite\wtest{Et utile...}%
+\immediate\closeout\wtest
+Contenu du fichier :\par
+\showfilecontent\rtest{writetest.txt}% affiche le contenu du fichier
+****************** Fin code ******************
+
+
+****************** Code 293 ******************
+\catcode`\@11
+\def\exactwrite#1{% #1=num\xE9ro de canal
+	\begingroup
+		\def\canal at write{#1}% sauvegarde le num\xE9ro de canal
+		\for\xx=0 to 255\do{\catcode\xx=12 }% donne \xE0 tous les octets le catcode 12
+		\exactwrite at i% aller lire le <car>
+}
+
+\def\exactwrite at i#1{% #1 est le <car> de catcode 12
+	\def\exactwrite at ii##1#1{% ##1 est le <texte> \xE0 envoyer vers le fichier
+		\exactwrite at iii##1\@nil% envoyer <texte> \xE0 \exactwrite at iii
+	}%
+	\exactwrite at ii% va lire tout ce qui se trouve jusqu'au prochain <car>
+}
+
+{\catcode`\^^M 12 \gdef\EOL at char{^^M}}% d\xE9finit le caract\xE8re <EOL> de catcode 12
+
+\def\exactwrite at iii#1\@nil{% #1 = <texte> \xE0 \xE9crire dans le fichier
+	\expsecond{\ifin{#1}}\EOL at char% si #1 contient "retour charriot"
+		{\write at line#1\@nil% \xE9crire la premi\xE8re ligne de #1
+		}
+		{\immediate\write\canal at write{#1}% sinon : derni\xE8re ligne atteinte, l'\xE9crire
+		\endgroup% puis sortir du groupe
+		}%
+}
+
+% les \expandafter provoquent le 1-d\xE9veloppement de \EOL at char :
+\expandafter\def\expandafter\write at line\expandafter#\expandafter1\EOL at char#2\@nil{%
+	\immediate\write\canal at write{#1}% \xE9crit la ligne (ce qui se trouve avant ^^M)
+	\exactwrite at iii#2\@nil% recommencer avec ce qui se trouve apr\xE8s "^^M"
+}
+\catcode`\@12
+
+\immediate\openout\wtest=writetest.txt % lie le canal \wtest au fichier
+\exactwrite\wtest|Programmer en \TeX{} est   facile !
+
+Et tr\xE8s utile.|
+\immediate\closeout\wtest% et fermer le fichier
+
+Le contenu du fichier "writetest.txt" est :\par
+"\showfilecontent\rtest{writetest.txt}"
+****************** Fin code ******************
+
+
+****************** Code 294 ******************
+\catcode`\@11
+\newcount\exo at number% compteur pour le num\xE9ro d'exercice
+
+\def\exocalctotal#1\endtotal{\edef\total at points{\dimtodec\dimexpr#1}}
+
+\def\initexo#1{%
+	\def\exo at canal{#1}% sauvegarde le canal d'\xE9criture
+	\exo at number=0 % initialiser le compteur d'exo
+	\iffileexists\exo at canal{\jobname.pts}% si le fichier .pts existe
+		{\input \jobname.pts }% le lire et ex\xE9cuter son contenu
+		{\def\total at points{\char`\#\char`\#}}% sinon, d\xE9finir un total alternatif
+	\immediate\openout\exo at canal=\jobname.pts % ouvrir le fichier .pts
+	\immediate\write\exo at canal{\noexpand\exocalctotal}% et commencer \xE0 y \xE9crire dedans
+}
+
+\def\exo#1{% d\xE9finti la macro qui affiche l'exercice
+	\bigbreak% sauter une grande espace verticale
+	\immediate\write\exo at canal{+#1}% \xE9crire "+#1" dans le fichier .pts
+	\advance\exo at number by 1 % incr\xE9menter le num\xE9ro de l'exercice
+	\noindent\vrule height1ex width1ex depth0pt % trace le carr\xE9
+	\kern1ex% ins\xE9rer une espace horizontale
+	{\bf Exercice \number\exo at number}% afficher "Exercice <nombre>"
+	\leaders\hbox to.5em{\hss.\hss}\hfill% afficher les pointill\xE9s
+	#1/\total at points%  puis #1/<total>
+	\smallbreak% composer la ligne pr\xE9c\xE9dente et sauter une espace verticale
+}
+
+\def\stopexo{%
+	\immediate\write\exo at canal{\relax\noexpand\endtotal}%
+	\immediate\closeout\exo at canal
+}
+\catcode`\@12
+\initexo\wtest
+
+\hfill{\bf Interrogation \xE9crite. Sujet : \TeX{}}\hfill\null
+\par
+\leavevmode\hfill\vrule height.4pt width 2cm depth0pt\hfill\null
+\exo{3pt}
+\xC9laborer un test \litterate/\ifonebyte{<texte>}{<vrai>}{<faux>}/ qui teste, pour une
+compilation avec un moteur 8 bits, si le \litterate/<texte>/ est cod\xE9 sur un seul
+octet. Ce test pourrait \xEAtre utilis\xE9 pour d\xE9terminer si l'encodage d'un document
+est \xE0 plusieurs octets (comme l'est UTF8) en prenant comme \litterate/<texte>/
+les caract\xE8res <<~\xE9~>>, <<~\xE0~>>, etc.
+
+\exo{5,5pt}
+Si \verb-#1- est un nombre entier, quel est le test fait par ce code ?
+\smallbreak
+\hfill
+\litterate/\if\string l\expandafter\firstto at nil\romannumeral#1\relax\@nil/
+\hfill\null
+
+\exo{4,5pt}
+On a vu que pour provoquer un $n$-d\xE9veloppement, les \litterate/\expandafter/se pla\xE7aient
+en nombre \xE9gal \xE0 $2^n-1$ devant chaque token pr\xE9c\xE9dant celui que l'on veut d\xE9velopper.
+Or, ce nombre est {\it impair\/}. Trouver un exemple ou un cas particulier o\xF9 il faut
+placer un nombre {\it pair\/} d'\litterate/\expandafter/ devant un token (on pourra 
+envisager le cas de 2 \litterate/\expandafter/).
+\stopexo
+****************** Fin code ******************
+
+
+****************** Code 295 ******************
+\def\identite{Foo Bar}% Pr\xE9nom Nom
+\def\beforespace#1 #2\nil{#1}
+\def\afterspace#1 #2\nil{#2}
+\def\prenom{\beforespace\identite\nil}
+\def\nom{\afterspace\identite\nil}
+Mon pr\xE9nom : \expandafter\expandafter\prenom
+
+Mon nom : \expandafter\expandafter\nom
+****************** Fin code ******************
+
+
+****************** Code 296 ******************
+\newlinechar`\^^J 
+\immediate\openout\wtest=test1.txt 
+\immediate\write\wtest{Une premi\xE8re ligne^^JEt une seconde.}
+\immediate\closeout\wtest 
+\showfilecontent\rtest{test1.txt}
+****************** Fin code ******************
+
+
+****************** Code 297 ******************
+\newlinechar`\^^J 
+\immediate\openout\wtest=test2.txt 
+\immediate\write\wtest{Une premi\xE8re ligne^^JEt une seconde.}
+\immediate\write\wtest{Et la derni\xE8re.}
+\immediate\closeout\wtest 
+
+{\endlinechar`\X % ins\xE8re "X" \xE0 chaque fin de ligne
+\openin\rtest=test2.txt % les fins de lignes sont comment\xE9es
+\loop%                    pour \xE9viter que \endlinechar 
+	\read\rtest to \foo%    ne soit ins\xE9r\xE9 \xE0 chaque fin de
+	\unless\ifeof\rtest%    ligne du code source
+	\meaning\foo\par%       affiche le texte de remplacement de \foo
+\repeat%
+\closein\rtest}%
+****************** Fin code ******************
+
+
+****************** Code 298 ******************
+\catcode`\@11
+\def\exactwrite#1{% #1=num\xE9ro de canal
+	\begingroup
+		\for\xx=0 to 255\do{\catcode\xx=12 }% donne \xE0 tous les octets le catcode 12
+		\newlinechar=`\^^M % caract\xE8re de fin de ligne = retour charriot
+		\exactwrite at i{#1}% donne le <canal> d'\xE9criture comme premier argument
+}
+
+\def\exactwrite at i#1#2{% #2 est le caract\xE8re d\xE9limiteur de catcode 12
+	\def\exactwrite at ii##1#2{% ##1 est le <texte> \xE0 envoyer vers le fichier
+		\immediate\write#1{##1}% \xE9crire le <texte> dans le fichier
+		\endgroup% puis, sortir du groupe
+	}%
+	\exactwrite at ii% traiter tout ce qui se trouve jusqu'au prochain #2
+}
+\catcode`\@12
+
+\immediate\openout\wtest=writetest.txt % lie le canal \wtest au fichier
+\exactwrite\wtest|Programmer en \TeX{} est   facile !
+
+Et tr\xE8s utile.|
+\immediate\closeout\wtest% et fermer le fichier
+
+Le contenu du fichier "writetest.txt" est :\par
+"\showfilecontent\rtest{writetest.txt}"
+****************** Fin code ******************
+
+
+****************** Code 299 ******************
+\newlinechar`\^^J 
+\message{^^JQuel est votre nom ? }
+\xread-1 to \username
+\message{Bonjour \username.^^J%
+Depuis combien d'ann\xE9es pratiquez-vous TeX ? }
+\read-1 to \yeartex 
+\message{%
+	\ifnum\yeartex<5 Cher \username, vous \xEAtes encore un d\xE9butant !
+	\else\ifnum\yeartex<10 Bravo \username, vous \xEAtes un TeXpert !
+	\else\ifnum\yeartex<15 F\xE9licitations \username, vous \xEAtes un TeXgourou.
+	\else Passez \xE0 autre chose, par exemple \xE0 Metafont et Metapost !
+	\fi\fi\fi^^J}
+****************** Fin code ******************
+
+
+****************** Code 300 ******************
+\catcode`\@11
+\def\answer at plus{+}\def\answer at minus{-}\def\answer at equal{=}%
+\def\nb at found#1{% macro appel\xE9e lorsque le nombre (argument #1) est trouv\xE9
+	\message{^^JVotre nombre est #1.^^JMerci d'avoir jou\xE9 avec moi.^^J}%
+}
+
+\def\nbguess#1#2{%
+	\message{Choisissez un nombre entre #1 et #2.^^J
+	Tapez entr\xE9e lorsque c'est fait.}%
+	\read-1 to \tex at guess% attend que l'on tape sur "entr\xE9e"
+	\nbguess at i{#1}{#2}%
+}
+
+\def\nbguess at i#1#2{%
+	\ifnum#1<#2  \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		% si #1<#2 (donc le nombre n'est pas trouv\xE9),
+		% mettre dans \tex at guess la troncature de la moyenne de #1 et #2
+		{\edef\tex at guess{\number\truncdiv{\numexpr#1+#2\relax}2}%
+		\message{Je propose \tex at guess.^^J% afficher sur le terminal
+		Votre nombre est-il plus grand (+), plus petit (-) ou \xE9gal (=) : }%
+		\read -1 to \user at answer% lire la r\xE9ponse de l'utilisateur
+		\edef\user at answer{%
+			\expandafter\firstto at nil\user at answer\relax\@nil% ne garder que le 1er caract\xE8re
+		}%
+		\ifxcase\user at answer% envisager les cas "+", "-" et "="
+			\answer at plus{\exparg\nbguess at i{\number\numexpr\tex at guess+1\relax}{#2}}%
+			\answer at minus{\expsecond{\nbguess at i{#1}}{\number\numexpr\tex at guess-1\relax}}%
+			\answer at equal{\nb at found\tex at guess}%
+		\elseif% si la r\xE9ponse ne commence pas par "+", "-" ou "="
+			\message{Je n'ai pas compris votre r\xE9ponse}% afficher message erreur
+			\nbguess at i{#1}{#2}% et recommencer avec les m\xEAmes nombres
+		\endif
+		}
+		% si #1>=#2, le nombre est trouv\xE9
+		{\nb at found{#1}}%
+}
+\catcode`\@12
+
+\nbguess{1}{100}
+****************** Fin code ******************
+
+
+****************** Code 301 ******************
+\def\syracuse#1{%
+	#1% affiche le nombre
+	\ifnum#1>1 % si le nombre est >1
+		, % afficher une virgule+espace
+		\ifodd#1 % s'il est pair
+			\exparg\syracuse% appeler la macro \syracuse
+			{\number\numexpr3*#1+1% avec 3*n+1
+			\expandafter\expandafter\expandafter}% apr\xE8s avoir rendu la macro terminale
+		\else % s'il est pair
+			\expandafter\syracuse\expandafter% appeler la macro \syracuse
+			{\number\numexpr#1/2% avec n/2
+			\expandafter\expandafter\expandafter}% apr\xE8s avoir rendu la macro terminale
+		\fi
+	\else% si le nombre est 1
+		.% afficher un point
+	\fi
+}
+a) \syracuse{20}\par
+b) \syracuse{14}\par
+c) \syracuse{99}\par
+d) \edef\foo{\syracuse{15}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 302 ******************
+\def\syracuse#1{%
+	#1% afficher le nombre
+	\ifnum#1>1 % si le nombre est >1
+		, % afficher une virgule+espace
+		\exparg\syracuse{% appeler la macro \syracuse
+			\number\numexpr% avec le nombre :
+				\ifodd#1 3*#1+1% 3n+1 si #1 est impair
+				\else #1/2%      n/2 sinon
+				\fi%
+			\expandafter}% avant de rendre la r\xE9cursivit\xE9 terminale
+	\else
+	.% si #1=1, afficher un point
+	\fi
+}
+a) \syracuse{20}\par
+b) \syracuse{14}\par
+c) \syracuse{99}\par
+d) \edef\foo{\syracuse{15}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 303 ******************
+\def\factorielle#1{%
+	\ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{1}% "1" si #1=0}
+		{#1*\exparg\factorielle{\number\numexpr#1-1}}% 
+}
+a) \factorielle{0}\qquad
+b) \factorielle{3}\qquad
+c) \edef\foo{\factorielle{8}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 304 ******************
+\catcode`\@11
+\def\factorielle#1{%
+	\number\numexpr\factorielle at i{#1}\relax% appelle \factorielle at i
+	% en lan\xE7ant le d\xE9veloppement maximal
+}
+\def\factorielle at i#1{%
+	\ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{1}% "1" si #1=
+		{#1*\exparg\factorielle at i{\number\numexpr#1-1}}% 
+}
+\catcode`\@12
+a) \factorielle{0}\qquad
+b) \factorielle{3}\qquad
+c) \edef\foo{\factorielle{8}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 305 ******************
+\catcode`\@11
+\def\PGCD#1#2{%
+	\ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{\PGCD at i{#2}{#1}}% si #1<#2, mettre #2 (le  grand) dans le premier argument
+		{\PGCD at i{#1}{#2}}%
+}
+
+\def\PGCD at i#1#2{% #1=a   #2=b avec a>b
+	\exptwoargs\PGCD at ii% appeler la macro r\xE9cursive avec
+			{\number\numexpr#1-#2*\truncdiv{#1}{#2}}% le reste de a/b
+			{#2}% et le divisieur b
+}
+
+\def\PGCD at ii#1#2{% #1=reste r   #2=diviseur b
+	\ifnum#1=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{#2}% si le reste est nul, renvoyer b
+		{\PGCD at i{#2}{#1}}% sinon, recommencer avec b et r
+}
+\catcode`\@12
+a) \PGCD{120}{75}\qquad
+b) \PGCD{64}{180}\qquad
+c) \PGCD{145}{64}\qquad
+d) \edef\foo{\PGCD{1612}{299}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 306 ******************
+\catcode`\@11
+\def\calcPGCD#1#2{%
+	\ifhmode\par\fi% si en mode horizontal, former le paragraphe
+	\ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{\calcPGCD at i{#2}{#1}}% si #1<#2, mettre #2 (le  grand) dans le premier argument
+		{\calcPGCD at i{#1}{#2}}%
+}
+
+\def\calcPGCD at i#1#2{% #1=a   #2=b avec a>b
+	\edef\calcPGCD at quotient{\number\truncdiv{#1}{#2}}% stocke le quotient
+	$#1=\calcPGCD at quotient\times#2% en mode maths, afficher "a=q*b" (\xE0 suivre)
+	\exptwoargs\calcPGCD at ii% appeler la macro r\xE9cursive avec
+			{\number\numexpr#1-#2*\calcPGCD at quotient}% le reste de a/b
+			{#2}% et le divisieur b
+}
+
+\def\calcPGCD at ii#1#2{% #1=reste r   #2=diviseur b
+	+#1$\par% (suite du mode math) afficher "+r", fermer le mode math et \par
+	\ifnum#1=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi%
+		{}% si le reste est nul, ne rien faire
+		{\calcPGCD at i{#2}{#1}}% sinon, recommencer avec b et r
+}
+\catcode`\@12
+\calcPGCD{39}{15}\medbreak
+\calcPGCD{1612}{299}
+****************** Fin code ******************
+
+
+****************** Code 307 ******************
+\frboxsep=0pt % encadrer au plus proche
+\leavevmode\frbox{$=$} n'est pas identique \xE0 \frbox{${}={}$}
+****************** Fin code ******************
+
+
+****************** Code 308 ******************
+\catcode`\@11
+\def\calcPGCD#1#2{%
+	\vtop{% mettre l'alignement dans une \vtop
+		\halign{% les "#" doivent \xEAtre doubl\xE9s puisqu'\xE0 l'int\xE9rieur d'une macro
+		$\hfil##$&${}=\hfil##$&${}\times##\hfil$&${}+##\hfil$% pr\xE9ambule
+		\cr% fin du pr\xE9ambule et d\xE9but de la premi\xE8re cellule
+		\ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			{\calcPGCD at i{#2}{#1}}% si #1<#2, mettre #2 (le  grand) dans le premier argument
+			{\calcPGCD at i{#1}{#2}}%
+		\crcr% fin de l'alignement
+		}%
+	}%
+}
+
+\def\calcPGCD at i#1#2{% #1=a   #2=b avec a>b
+	\xdef\calcPGCD at quotient{\number\truncdiv{#1}{#2}}% stocke le quotient
+	#1 & \calcPGCD at quotient & #2 &% afficher "a=q*b" (\xE0 suivre)
+	\exptwoargs\calcPGCD at ii% appeler la macro r\xE9cursive avec
+			{\number\numexpr#1-#2*\calcPGCD at quotient}% le reste de a/b
+			{#2}% et le divisieur b
+}
+
+\def\calcPGCD at ii#1#2{% #1=reste r   #2=diviseur b
+	#1% (suite de l'alignement) afficher "+r"
+	\cr% et terminer la ligne en cours
+	\ifnum#1=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi%
+		{}% si le reste est nul, ne rien faire
+		{\calcPGCD at i{#2}{#1}}% sinon, recommencer avec b et r
+}
+\catcode`\@12
+a) \calcPGCD{39}{15}\medbreak
+b) \calcPGCD{1612}{299}
+****************** Fin code ******************
+
+
+****************** Code 309 ******************
+\catcode`\@11
+\def\baseconv#1{%
+	\unless\ifnum#1=\z@ % si #1 est diff\xE9rent de 0
+		\number\numexpr#1-2*\truncdiv{#1}2\relax% \xE9crire le reste
+		\exparg\baseconv{\number\truncdiv{#1}2\expandafter}% recommencer avec #1/2
+	\fi% apr\xE8s que le \fi ait \xE9t\xE9 lu
+}
+\catcode`\@12
+a) \baseconv{43}\qquad
+b) \baseconv{32}\qquad
+c) \edef\foo{\baseconv{159}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 310 ******************
+\catcode`\@11
+\def\baseconv#1{%
+	\baseconv at i{}{#1}%
+}
+
+\def\baseconv at i#1#2{% #1=restes   #2=n
+	\ifnum#2=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi% si n=0
+		{#1}% si <n>=0, afficher tous les restes
+		{% sinon, recommencer en
+		\exptwoargs\baseconv at i% ajoutant le reste courant avant #1
+			{\number\numexpr#2-2*\truncdiv{#2}2\relax #1}
+			{\number\truncdiv{#2}2}% et en prenant n:=n/2
+		}%
+}
+
+\catcode`\@12
+a) \baseconv{43}\qquad
+b) \baseconv{32}\qquad
+c) \edef\foo{\baseconv{159}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 311 ******************
+\catcode`\@11
+\def\z@@{\expandafter\z@\expandafter}
+\def\basedigit#1{%
+	\ifcase#1
+		\z@@ 0%
+		\or\z@@ 1\or\z@@ 2\or\z@@ 3\or\z@@ 4\or\z@@ 5\or\z@@ 6\or\z@@ 7%
+		\or\z@@ 8\or\z@@ 9\or\z@@ A\or\z@@ B\or\z@@ C\or\z@@ D\or\z@@ E%
+		\or\z@@ F\or\z@@ G\or\z@@ H\or\z@@ I\or\z@@ J\or\z@@ K\or\z@@ L%
+		\or\z@@ M\or\z@@ N\or\z@@ O\or\z@@ P\or\z@@ Q\or\z@@ R\or\z@@ S%
+		\or\z@@ T\or\z@@ U\or\z@@ V\or\z@@ W\or\z@@ X\or\z@@ Y\or\z@@ Z%
+	\fi
+}
+\long\def\>#1<{\detokenize{#1}}
+a) \expandafter\>\romannumeral\basedigit{23}<\quad
+b) \expandafter\>\romannumeral\basedigit{6}<
+\catcode`@12
+****************** Fin code ******************
+
+
+****************** Code 312 ******************
+\catcode`\@11
+\def\baseconv#1#2{% #1=base  #2=nombre \xE0 convertir
+	\ifnum#1<37 % base maxi = 36 (10 signes chiffres + 26 signes lettres)
+		\antefi
+		\baseconv at i{}{#2}{#1}%
+	\fi
+}
+\def\baseconv at i#1#2#3{% #1=restes  #2=n  #3=base
+	\ifnum#2=\z@ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{#1}% si n=0, afficher tous les restes
+		{% si non, transmettre en dernier argument
+		\expsecond{\baseconv at ii{#1}{#2}{#3}}%
+			{\number\truncdiv{#2}{#3}}% le quotient
+		}%
+}
+\def\baseconv at ii#1#2#3#4{% #1=restes  #2=n  #3=base  #4=q
+	\exparg\baseconv at i% recommencer, en ajoutant le <chiffre> avant les restes
+		{\romannumeral\basedigit{\number\numexpr#2-#4*#3\relax}#1}%
+		{#4}% et en rempla\xE7ant n par q
+		{#3}%
+}
+\def\z@@{\expandafter\z@\expandafter}%
+\def\basedigit#1{%
+	\ifcase#1
+		\z@@ 0%
+		\or\z@@ 1\or\z@@ 2\or\z@@ 3\or\z@@ 4\or\z@@ 5\or\z@@ 6\or\z@@ 7%
+		\or\z@@ 8\or\z@@ 9\or\z@@ A\or\z@@ B\or\z@@ C\or\z@@ D\or\z@@ E%
+		\or\z@@ F\or\z@@ G\or\z@@ H\or\z@@ I\or\z@@ J\or\z@@ K\or\z@@ L%
+		\or\z@@ M\or\z@@ N\or\z@@ O\or\z@@ P\or\z@@ Q\or\z@@ R\or\z@@ S%
+		\or\z@@ T\or\z@@ U\or\z@@ V\or\z@@ W\or\z@@ X\or\z@@ Y\or\z@@ Z%
+	\fi
+}
+\catcode`\@12
+a) "\baseconv{20}{21587}"\qquad
+b) "\baseconv{16}{32}"\qquad
+c) \edef\foo{\baseconv{16}{159}}%
+   "\meaning\foo"\qquad
+d) "\baseconv{2}{43}"
+****************** Fin code ******************
+
+
+****************** Code 313 ******************
+\catcode`\@11
+\def\quark at list{\quark at list}% quark de fin de liste
+\def\finditem#1{% #1 = \<macrolist>, la position est lue plus tard par \finditem at i
+	\exparg\finditem at i{#1}% 1-d\xE9veloppe la \<macrolist>
+}
+\def\finditem at i#1#2{% #1 = liste   #2=position cherch\xE9e
+	\finditem at ii{1}{#2}#1,\quark at list,% appelle la macro r\xE9cursive
+}
+\def\finditem at ii#1#2#3,{% #1=position courante  #2=position cherch\xE9e  #3=\xE9l\xE9ment courant
+	\ifx\quark at list#3\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{}% si la fin de liste est atteinte, ne rien renvoyer
+		{% sinon
+		\ifnum#1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			{% si la position est la bonne
+			\finditem at iii{#3}% renvoyer #3 et manger les \xE9l\xE9ments restants
+			}
+			{% si la position n'est pas la bonne, recommencer en incr\xE9mentant #1
+			\exparg\finditem at ii{\number\numexpr#1+1}{#2}%
+			}%
+		}%
+}
+\def\finditem at iii#1#2\quark at list,{% renvoyer #1 et manger le reste de la liste
+	#1%
+}
+\catcode`\@12
+\def\liste{a,bcd,{ef},g,hij,kl}
+a) \edef\foo{\finditem\liste5}\meaning\foo\qquad
+b) \edef\bar{\finditem\liste3}\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 314 ******************
+\catcode`\@11
+\def\quark at list{\quark at list}% quark de fin de liste
+\def\finditem#1{% #1 = \<macro>, la position est lue plus tard par \finditem at i
+	\exparg\finditem at i{#1}% 1-d\xE9veloppe la \<macro>
+}
+\def\finditem at i#1#2{% #1 = liste   #2=position cherch\xE9e
+	\ifnum#2>\z@% ne faire quelque chose que si la position est >0
+		\antefi
+		\finditem at ii{1}{#2}\relax#1,\quark at list,% appelle la macro r\xE9cursive
+	\fi
+}
+\def\finditem at ii#1#2#3,{% #1=position courante  #2=position cherch\xE9  #3=\xE9l\xE9ment courant
+	\expandafter\ifx\expandafter\quark at list\gobone#3%
+	\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{}% si la fin de liste est atteinte, ne rien renvoyer
+		{% sinon
+		\ifnum#1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			{% si la position est la bonne
+			\finditem at iii{#3}% renvoyer #3 et manger les \xE9l\xE9ments restants
+			}
+			{% si la position n'est pas la bonne, recommencer en incr\xE9mentant #1
+			\exparg\finditem at ii{\number\numexpr#1+1}{#2}\relax
+			}%
+		}%
+}
+\def\finditem at iii#1#2\quark at list,{% renvoyer #1 et manger le reste de la liste
+	\gobone#1%
+}
+\def\finditemtocs#1#2#3{% #1 = \<macro>  #2=position  #3=macro \xE0 d\xE9finir
+	\def\finditemtocs at iii##1##2\quark at list,{% renvoyer #1 et manger le reste de la liste
+		\expandafter\def\expandafter#3\expandafter{\gobone##1}%
+	}%
+	\let#3=\empty
+	\exparg\finditemtocs at i{#1}{#2}% 1-d\xE9veloppe la \<macro>
+}
+\def\finditemtocs at i#1#2{% #1 = liste   #2=position cherch\xE9e
+	\ifnum#2>\z@% ne faire quelque chose que si la position est >0
+		\antefi\finditemtocs at ii{1}{#2}\relax#1,\quark at list,% appelle la macro r\xE9cursive
+	\fi
+}
+\def\finditemtocs at ii#1#2#3,{%
+% #1=position courante  #2=position cherch\xE9  #3=\relax + \xE9l\xE9ment courant
+	\expandafter\ifx\expandafter\quark at list\gobone#3%
+	\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{}% si fin de liste ne rien faire. Sinon, si position bonne
+		{\ifnum#1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			{\finditemtocs at iii{#3}% renvoyer #3 et manger les \xE9l\xE9ments restants
+			}% si la position n'est pas la bonne, recommencer en incr\xE9mentant #1
+			{\exparg\finditemtocs at ii{\number\numexpr#1+1}{#2}\relax%
+			}%
+		}%
+}
+\catcode`\@12
+\def\liste{a,bcd,{ef},g,hij,kl}
+a) "\finditem\liste5"\qquad
+b) \edef\bar{\finditem\liste3}\meaning\bar\qquad
+c) \finditemtocs\liste{3}\foo\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 315 ******************
+\catcode`\@11
+\def\quark at list{\quark at list}% quark de fin de liste
+\def\positem#1{% #1 = \<macrolist>, la position est lue plus tard par \positem at i
+	\def\positem at endprocess{\pos at item}% hook : afficher la position
+	\exparg\positem at i{#1}% 1-d\xE9veloppe la \<macrolist>
+}
+\def\positem at i#1#2{% #1 = liste   #2=\xE9l\xE9ment cherch\xE9
+	\def\sought at item{#2}% d\xE9finir l'\xE9l\xE9ment cherch\xE9
+	\positem at ii{1}\relax#1,\quark at list,% appelle la macro r\xE9cursive
+}
+\def\positem at ii#1#2,{% #1=position courante  #2=\relax + \xE9l\xE9ment courant
+	\expandafter\def\expandafter\current at item\expandafter{\gobone#2}%
+	\ifx\current at item\quark at list\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{\def\pos at item{0}% si la fin de liste est atteinte, renvoyer 0
+		\positem at endprocess% et aller au hook
+		}% sinon
+		{\ifx\current at item\sought at item\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			{\def\pos at item{#1}% si la position est la bonne, d\xE9finir la position
+			\positem at goblist% et manger les \xE9l\xE9ments restants
+			}% si la position n'est pas la bonne, recommencer en incr\xE9mentant #1
+			{\exparg\positem at ii{\number\numexpr#1+1}\relax
+			}%
+		}%
+}
+\def\positem at goblist#1\quark at list,{\positem at endprocess}% manger la liste et aller au hook
+
+\def\positemtocs#1#2#3{% #1=\<macrolist>  #2=\xE9l\xE9ment \xE0 chercher  #3=macro \xE0 d\xE9finir
+	\def\positem at endprocess{\let#3=\pos at item}% hook : mettre le r\xE9sultat dans #3
+	\exparg\positem at i{#1}{#2}% 1-d\xE9veloppe la \<macrolist>
+}
+
+\catcode`\@12
+\def\liste{a,bcd,{ef},g,hij,,kl}
+a) \positem\liste{g}\qquad
+b) \positem\liste{ef}\qquad
+c) \positem\liste{{ef}}\qquad
+d) \positem\liste{}\medbreak
+
+\def\liste{a,bcd,{ef},g,hij,,kl}
+a) \positemtocs\liste{g}\foo\meaning\foo\qquad
+b) \positemtocs\liste{ef}\foo\meaning\foo\qquad
+c) \positemtocs\liste{{ef}}\foo\meaning\foo\qquad
+d) \positemtocs\liste{}\foo\meaning\foo\qquad
+****************** Fin code ******************
+
+
+****************** Code 316 ******************
+\catcode`\@11
+\def\quark at list{\quark at list}% quark de fin de liste
+\def\insitem#1#2#3{% #1 = macro   #2=position cherch\xE9e   #3=\xE9l\xE9ment \xE0 ins\xE9rer
+	\let\item at list=\empty
+	\ifnum#2<1 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		% si position < 1
+		{\addtomacro\item at list{#3,}% ajouter l'\xE9lement \xE0 ins\xE9rer en premier
+		\eaddtomacro\item at list#1% puis la liste enti\xE8re
+		}
+		% si la position  > 1
+		{% d\xE9finir la macro r\xE9cursive
+		\def\insitem at i##1##2,{% ##1 = position courante  ##2=\relax + \xE9l\xE9ment courant
+			\expandafter\ifx\expandafter\quark at list\gobone##2%
+			\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+				{\addtomacro\item at list{#3}}% si fin de liste, ajouter l'\xE9l\xE9ment en dernier
+				{% sinon, si la position cherch\xE9e est atteinte
+				\ifnum##1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+					{\addtomacro\item at list{#3,}% ajouter l'\xE9lement
+					\add at remainlist##2,% et ##2 (en supprimant le \relax) et le reste
+					}% si la position n'est pas atteinte
+					{\eaddtomacro\item at list{\gobone##2,}% ajouter l'\xE9l\xE9ment
+					\exparg\insitem at i{\number\numexpr##1+1}\relax% et recommencer
+					}%
+				}%
+			}%
+		% appel de la macro r\xE9cursive
+		\expandafter\insitem at i\expandafter1\expandafter\relax#1,\quark at list,%
+		}%
+	\let#1=\item at list% rendre #1 \xE9gal au r\xE9sultat
+}
+
+\def\add at remainlist#1,\quark at list,{%
+	\eaddtomacro\item at list{\gobone#1}% ajouter #1 ainsi que les autres
+}
+\catcode`\@12
+\def\liste{a,bra,{cA},da,brA}\insitem\liste3{XX}\meaning\liste\par
+\def\liste{a,bra,{cA},da,brA}\insitem\liste0{XX}\meaning\liste\par
+\def\liste{a,bra,{cA},da,brA}\insitem\liste9{XX}\meaning\liste
+****************** Fin code ******************
+
+
+****************** Code 317 ******************
+\catcode`\@11
+\def\quark at list{\quark at list}% quark de fin de liste
+\def\delitem#1#2{% #1 = macro   #2=position cherch\xE9e
+	\ifnum#2>0 % ne faire quelque chose que si la position est >0
+		\def\delitem at i##1##2,{% ##1 = position courante  ##2=\relax + \xE9l\xE9ment courant
+			\expandafter\ifx\expandafter\quark at list\gobone##2%
+			\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+				{}% si fin de liste, ne rien faire
+				{% sinon, si la position cherch\xE9e est atteinte
+				\ifnum##1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+					{\add at reaminingitems% et ##2 (en supprimant le \relax) et le reste
+					}% si la position n'est pas la bonne
+					{\eaddtomacro\item at list{\gobone##2,}% ajouter l'\xE9l\xE9ment
+					\exparg\delitem at i{\number\numexpr##1+1}\relax% et recommencer
+					}%
+				}%
+			}%
+		\let\item at list=\empty% initialiser la macro tempporaire
+		% appel de la macro r\xE9cursive
+		\expandafter\delitem at i\expandafter1\expandafter\relax#1,\quark at list,%
+		\let#1=\item at list% rendre #1 \xE9gal au r\xE9sultat
+	\fi
+}
+
+\def\add at reaminingitems#1\quark at list,{%
+	\eaddtomacro\item at list{#1}% ajouter tout jusqu'au quark
+}
+\catcode`\@12
+\for\xx=0 to 8 \do{%
+\def\liste{a,bcd,{ef},g,hij,kl}
+position \xx{} : \expandafter\delitem\expandafter\liste\xx\meaning\liste.\par
+}
+****************** Fin code ******************
+
+
+****************** Code 318 ******************
+\catcode`\@11
+\def\moveitem#1#2#3{% #1 = liste, #2=position d\xE9part, #3=position arriv\xE9e
+	\ifnum#2>0 % ne faire quemque chose que si #2>0
+		\finditemtocs#1{#2}\temp at item% sauvegarder l'\xE9l\xE9ment
+		\delitem#1{#2}% supprimer l'\xE9l\xE9ment
+		\expsecond{\insitem#1{#3}}\temp at item% ins\xE9rer l'\xE9l\xE9ment
+	\fi
+}
+\catcode`\@12
+% d\xE9place "b" en 5e position
+a) \def\liste{a,b,c,d,e,f} \moveitem\liste25 "\liste"\par
+% d\xE9place "d" en 1e position
+b) \def\liste{a,b,c,d,e,f} \moveitem\liste41 "\liste"\par
+% d\xE9place "c" en 9e position
+c) \def\liste{a,b,c,d,e,f} \moveitem\liste39 \liste"\par
+% position d\xE9part=0 -> sans effet
+d) \def\liste{a,b,c,d,e,f} \moveitem\liste02 "\liste"
+****************** Fin code ******************
+
+
+****************** Code 319 ******************
+\catcode`\@11
+\def\runlist#1\with#2{% #1=liste #2=macro
+	\def\runlist at i##1,{%
+		\ifx\quark at list##1\relax\else% si la fin n'est pas atteinte
+			\addtomacro\collect at run{#2{##1}}% ajouter "\<macro>{<\xE9l\xE9ment>}""
+			\expandafter\runlist at i% et recommencer en lisant l'\xE9l\xE9ment suivant
+		\fi
+	}%
+	\begingroup% fait la collecte dans un groupe
+		\let\collect at run=\empty% initialiser la macro
+		\expandafter\runlist at i#1,\quark at list,% appeler \runlist at i
+	\expandafter\endgroup% ferme le groupe et d\xE9truit \collect at run
+	\collect at run% apr\xE8s l'avoir d\xE9velopp\xE9 !
+}
+\catcode`\@12
+\newcount\foocnt
+\foocnt=0 % compteur utilis\xE9 pour num\xE9roter les \xE9l\xE9ments dans la macro \foo
+\def\foo#1{% la macro qui va ex\xE9cuter chaque \xE9l\xE9ment de la liste. #1 = l'\xE9l\xE9ment
+	\advance\foocnt1 % incr\xE9mente le compteur
+	L'argument \number\foocnt\ est : {\bf #1}\par%
+}
+\def\liste{a,bra,ca,da,BRA}%
+\runlist\liste\with\foo%
+****************** Fin code ******************
+
+
+****************** Code 320 ******************
+\catcode`\@11
+\def\ifspacefirst#1{%
+	\expandafter\ifspacefirst at i\detokenize{#1W} \@nil% "W" se pr\xE9munit d'un argument vide
+}
+\def\ifspacefirst at i#1 #2\@nil{\ifempty{#1}}% renvoyer vrai s'il n'y a rien avant " "
+\catcode`\@12
+a) \ifspacefirst{a bc d}{vrai}{faux}\qquad
+b) \ifspacefirst{ a bc d}{vrai}{faux}\qquad
+c) \ifspacefirst{ }{vrai}{faux}\qquad
+d) \ifspacefirst{}{vrai}{faux}\qquad
+e) \ifspacefirst{{ } }{vrai}{faux}\qquad
+f) \ifspacefirst{ {x} }{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 321 ******************
+\catcode`\@11
+\expandafter\def\expandafter\gobspace\space{}
+
+\def\removefirstspaces#1{%
+	\ifspacefirst{#1}% si #1 commence par un espace
+		{\exparg\removefirstspaces{\gobspace#1}}% recommencer sans le 1er espace
+		{#1}% sinon, renvoyer l'argument
+}
+\catcode`\@12
+a) "\removefirstspaces{12 {\bf3}4 567}"\qquad
+b) "\removefirstspaces{ 12 {\bf3}4 567}"\qquad
+c) \edef\foo{\space\space\space 12 34 567}
+   "\exparg\removefirstspaces\foo"
+****************** Fin code ******************
+
+
+****************** Code 322 ******************
+\catcode`\@11
+\def\removefirstspaces{%
+	\romannumeral% lance le d\xE9veloppement maximal
+	\removefirstspaces at i% et passe la main \xE0 la macro r\xE9cursive
+}
+
+\def\removefirstspaces at i#1{%
+	\ifspacefirst{#1}% si #1 commence par un espace
+		{\exparg\removefirstspaces at i{\gobspace#1}}% recommencer sans le 1er espace
+		{\z@#1}% sinon, renvoyer l'argument o\xF9 \z@ stoppe l'action de \romannumeral
+}
+\catcode`\@12
+\long\def\>#1<{"\detokenize{#1}"}
+
+a) \expandafter\expandafter\expandafter\>\removefirstspaces{12 {\bf3}4 567}<\qquad
+b) \expandafter\expandafter\expandafter\>\removefirstspaces{ 12 {\bf3}4 567}<\qquad
+c) "\removefirstspaces{ 12 {\bf3}4 }"
+****************** Fin code ******************
+
+
+****************** Code 323 ******************
+\catcode`\@11
+\edef\catcodezero at saved{\number\catcode0 }% stocke le catcode de ^^00
+\catcode0=12 % le modifie \xE0 12
+\def\removelastspaces#1{%
+	\romannumeral% lance le d\xE9veloppement maximal
+	\removelastspaces at i\relax#1^^00 ^^00\@nil% mettre un \relax au d\xE9but
+	                                         % et passer la main \xE0 \removelastspaces at i
+}
+\def\removelastspaces at i#1 ^^00{% prendre ce qui est avant " W"
+	\removelastspaces at ii#1^^00% ajouter "W"
+}
+\def\removelastspaces at ii#1^^00#2\@nil{% #1=ce qui est avant "W"  #2=reliquat
+	\ifspacefirst{#2}% si le reliquat commence par un espace
+		{\removelastspaces at i#1^^00 ^^00\@nil}% recommencer sans passer par \removelastspaces
+		{\expandafter\z@\gobone#1}% sinon supprimer le \relax ajout\xE9 au d\xE9but
+		                          % et stopper l'action de \romannumeral avec \z@
+}
+\catcode0=\catcodezero at saved\relax% restaure le catcode de ^^00
+\catcode`\@12
+\long\def\>#1<{"\detokenize{#1}"}
+
+a) \expandafter\expandafter\expandafter\>\removelastspaces{ 12 {\bf3}4 }<\qquad
+b) \expandafter\expandafter\expandafter\>\removelastspaces{12 {\bf3}4}<\qquad
+c) "\removelastspaces{ 12 {\bf3}4 }"
+****************** Fin code ******************
+
+
+****************** Code 324 ******************
+\catcode`\@11
+\def\removetrailspaces#1{%
+	\romannumeral% lance le d\xE9veloppement maximal
+		\expandafter\expandafter\expandafter% le pont d'\expandafter
+	\removelastspaces
+		\expandafter\expandafter\expandafter% fait agir \removefirstspaces en premier
+	{%
+		\expandafter\expandafter\expandafter
+	\z@% stoppe le d\xE9veloppement initi\xE9 par \romannumeral
+	\removefirstspaces{#1}%
+	}%
+}
+\catcode`\@12
+\long\def\>#1<{"\detokenize{#1}"}
+
+a) \expandafter\expandafter\expandafter\>\removetrailspaces{ 12 {\bf3}4 }<\qquad
+b) \expandafter\expandafter\expandafter\>\removetrailspaces{12 {\bf3}4}<\par
+c) \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter
+   \foo\expandafter\expandafter\expandafter{\removetrailspaces{ 12 {\bf3}4 }}%
+   signification : \meaning\foo.\par
+c) ex\xE9cution : "\foo"\par
+d) "\removetrailspaces{ 12 {\bf3}4 }"
+****************** Fin code ******************
+
+
+****************** Code 325 ******************
+\catcode`\@11
+\def\sanitizelist#1{% #1 = liste
+	\let\item at list\empty% initialise le r\xE9ceptacle de la liste assainie
+	\def\sanitizelist at endprocess{% d\xE9finit le hook de fin
+		\expandafter\remove at lastcomma\item at list\@nil% supprimer derni\xE8re virgule
+		\let#1=\item at list% et assigner le r\xE9sultat \xE0 #1
+	}%
+	\expandafter\sanitizelist at i\expandafter\relax#1,\quark at list,% aller \xE0 la macro r\xE9cursive
+}
+
+\def\sanitizelist at i#1,{% #1="\relax" + \xE9l\xE9ment courant
+	\expandafter\ifx\expandafter\quark at list\gobone#1%
+	\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{\sanitizelist at endprocess% si fin de liste, hook de fin
+		}% si la fin de la liste n'est pas atteinte :
+		{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
+			\addtomacro% 1-d\xE9velopper \gobone pour retirer \relax
+		\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
+			\item at list% puis 2-d\xE9velopper \removetrailspaces
+		\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
+			{\expandafter\removetrailspaces\expandafter{\gobone#1},}% "#1"
+		\sanitizelist at i\relax% et continuer avec l'\xE9l\xE9ment suivant
+		}%
+}
+
+\catcode`\@12
+\frboxsep=0pt % encadrer au plus proche
+\def\foo#1{\frbox{\tt\strut#1} }% boite avec un strut et en fonte "tt" puis espace
+\def\liste{ Programmer, en \TeX{} ,est   ,{\bf facile}, et utile }
+a) \runlist\liste\with\foo% encadrer les items
+
+b) \sanitizelist\liste% supprimer les espaces inutiles des items
+   \runlist\liste\with\foo
+****************** Fin code ******************
+
+
+****************** Code 326 ******************
+\catcode`\@11
+\def\boxsentence#1{%
+	\leavevmode% se mettre en mode horizontal
+	\boxsentence at i#1\quark% transmet "#1+\quark" \xE0 boxsentence at i
+}
+\def\boxsentence at i#1{% #1= argument lu
+	\def\current at arg{#1}% stocke l'argument dans une macro temporaire
+	\unless\ifx\quark\current at arg% si la fin n'est  pas atteinte
+		\frbox{#1}% encadrer cet argument
+		\expandafter\boxsentence at i% lire l'argument suivant
+	\fi
+}
+\catcode`@12
+\frboxsep=1pt \frboxrule=0.2pt 
+\boxsentence{Programmer en \TeX\ est facile}
+****************** Fin code ******************
+
+
+****************** Code 327 ******************
+\catcode`\@11
+\edef\star at macro{\string *}% stocke une \xE9toile de catcode 12
+\def\expo#1{%
+	\def\temp at arg{#1}% stocke l'argument lu
+	\ifx\star at macro\temp at arg\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{% si l'argument est une \xE9toile de catcode 12
+		$^\dag$% affiche une dague
+		}% sinon
+		{$^\ddag$% affiche une double dague
+		{#1}% puis r\xE9-\xE9crit l'argument {#1}
+		}%
+}
+A\expo B\expo*C
+****************** Fin code ******************
+
+
+****************** Code 328 ******************
+\def\boxsentence#1{%
+	\readtok#1\quark% met le token d'arr\xEAt \quark \xE0 la fin de #1
+}
+\def\readtok{\afterassignment\cmptok\let\nxttok= }
+\def\cmptok{%
+	\unless\ifx\nxttok\quark% si la fin n'est pas atteinte
+		\frbox{\nxttok}%  encadrer le token lu
+		\expandafter\readtok% puis aller lire le suivant
+	\fi
+}
+\frboxsep=1pt \frboxrule=0.2pt 
+\leavevmode\boxsentence{Programmer en \TeX\ est facile}
+****************** Fin code ******************
+
+
+****************** Code 329 ******************
+\def\permutstart{\afterassignment\cmptok\let\nxttok= }
+\def\permutend{\permutend}%
+\def\cmptok{%
+	\unless\ifx\permutend\nxttok% tant que la fin n'est pas atteinte :
+		\ifxcase\nxttok
+		ae% si le token lu est "a", afficher un "e"
+		ei io ou uy ya% etc pour les autres lettres
+		\elseif
+			\nxttok% si ce n'est aucune voyelle, afficher le token
+		\endif
+		\expandafter\permutstart% aller lire le token suivant
+	\fi
+}
+\permutstart Un "a" puis "e puis "i" ensuite, un "o", un "u" et "y".\permutend
+****************** Fin code ******************
+
+
+****************** Code 330 ******************
+\def\boxsentence#1{\readtok#1\boxsentence}
+\def\readtok{\afterassignment\cmptok\let\nxttok= }
+\def\cmptok{%
+	%\show\nxttok% \xE0 d\xE9commenter pour d\xE9bogage
+	\unless\ifx\nxttok\boxsentence
+		\frbox{\nxttok}%
+		\expandafter\readtok
+	\fi
+}
+\frboxsep=1pt \frboxrule=0.2pt 
+\leavevmode\boxsentence{Pro{gra}mmer en \TeX\ est facile}
+****************** Fin code ******************
+
+
+****************** Code 331 ******************
+\catcode`\@11
+\def\Litterate{%
+	\begingroup% ouvrir un groupe
+		\tt% et adopter une fonte \xE0 chasse fixe
+		\afterassignment\Litterate at i% apr\xE8s l'assignation, aller \xE0 \Litterate at i
+		\expandafter\let\expandafter\lim at tok\expandafter=\string% \lim at tok = token d\xE9limiteur
+}
+\def\Litterate at i{%
+		\afterassignment\Litterate at ii%apr\xE8s avoir lu le prochain token, aller \xE0 \Litterate at ii
+		\expandafter\let\expandafter\nxttok\expandafter=\string% lit le token suivant
+}
+\def\Litterate at ii{%
+	\ifx\nxttok\lim at tok% si le token suivant="token d\xE9limiteur"
+		\endgroup% fermer le groupe et finir
+	\else
+		\nxttok% sinon, afficher ce token
+		\expandafter\Litterate at i% et lire le token suivant
+	\fi
+}
+\catcode`\@12
+\Litterate|Programmer     en \TeX {} est << facile >> !|
+****************** Fin code ******************
+
+
+****************** Code 332 ******************
+\catcode`\@11
+\def\Litterate{%
+	\begingroup% ouvrir un groupe
+		\tt% et adopter une fonte \xE0 chasse fixe
+		\afterassignment\Litterate at i% apr\xE8s l'assignation, aller \xE0 \Litterate at i
+		\expandafter\let\expandafter\lim at tok\expandafter=\string% \lim at tok = token d\xE9limiteur
+}
+\def\Litterate at i{%
+	\afterassignment\Litterate at ii% apr\xE8s avoir lu un token, aller \xE0 \Litterate at ii
+		\expandafter\expandafter\expandafter% 1-d\xE9velopper \string
+	\let
+		\expandafter\expandafter\expandafter% puis 1-d\xE9velopper \space en " "
+	\nxttok
+		\expandafter\expandafter\expandafter
+	=\expandafter\space\string% et lire le token obtenu
+}
+\def\Litterate at ii{%
+	\ifx\nxttok\lim at tok% si le token suivant="token d\xE9limiteur"
+		\endgroup% fermer le groupe et finir
+	\else
+		\nxttok% sinon, afficher ce token
+		\expandafter\Litterate at i% et lire le token suivant
+	\fi
+}
+\catcode`\@12
+\Litterate|Programmer     en \TeX {} est << facile >> : $~$^_#|
+****************** Fin code ******************
+
+
+****************** Code 333 ******************
+\catcode`@11
+\newskip\ltr at spc
+\def\letterspace#1#2{%
+	\ltr at spc=#1\relax % assigne le ressort
+	\letterspace at i#2\letterspace at i% appelle la macro \letterspace at i
+}
+\def\letterspace at i{%
+	\afterassignment\letterspace at ii
+	\let\nxttok=
+}
+\def\letterspace at ii{%
+	\ifx\nxttok\letterspace at i% si la fin est atteinte
+		\unskip% supprimer le dernier ressort qui est de trop
+	\else
+		\nxttok% afficher le token
+		\hskip\ltr at spc\relax% ins\xE8re le ressort
+		\expandafter\letterspace at i% va lire le token suivant
+	\fi
+}
+\catcode`@12
+Voici "\letterspace{0.3em}{des lettres espac\xE9es}"
+et voici "\letterspace{-0.075em}{de la compression}".
+****************** Fin code ******************
+
+
+****************** Code 334 ******************
+\catcode`@11
+\newcount\test at cnt
+\def\ifinteger#1{%
+	\ifstart{#1}{-}% si "-" est au d\xE9but de #1
+		{\exparg\ifinteger{\gobone#1}% l'enlever et recommencer
+		}
+		{\ifempty{#1}% sinon, si #1 est vide
+			\secondoftwo% lire l'argument <faux>
+			{\afterassignment\after at number% sinon, apr\xE8s l'assignation, aller \xE0 \after at number
+			\test at cnt=0#1\relax% faire l'assignation
+			                   %(\relax termine le nombre et n'est pas mang\xE9)
+			}%
+		}%
+}
+\def\after at number#1\relax{% #1 est ce qui reste apr\xE8s l'assignation
+	\ifempty{#1}% teste si #1 est vide et lit l'argument <vrai> ou <faux> qui suit
+}
+
+\catcode`@12
+1) \ifinteger{5644}{oui}{non}\qquad
+2) \ifinteger{-987}{oui}{non}\qquad
+3) \ifinteger{6a87}{oui}{non}\qquad
+4) \ifinteger{abcd}{oui}{non}\qquad
+5) \ifinteger{-a}{oui}{non}\qquad
+6) \ifinteger{-}{oui}{non}\qquad
+7) \ifinteger{3.14}{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 335 ******************
+\catcode`\@11
+\def\teststar{%
+	\futurelet\nxttok\teststar at i% % pioche le token suivant puis aller \xE0 \teststar at i
+}
+\def\teststar at i{%
+	\ifx *\nxttok\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{% si le token suivant est une \xE9toile
+		\afterassignment\teststar at bf% apr\xE8s avoir lu "*", aller \xE0 \teststar at bf
+		\let\nxttok= % lire l'\xE9toile
+		}% si le token n'est pas une \xE9toile
+		{\teststar at it% aller \xE0 \teststar at it
+		}%
+}
+\def\teststar at bf#1{{\bf#1}}% lit l'argument et le compose en gras dans un groupe
+\def\teststar at it#1{{\it#1\/}}% lit l'argument et le compose en italique
+\catcode`\@12
+Un essai \teststar{r\xE9ussi} et un essai \teststar*{\xE9toil\xE9} r\xE9ussi aussi.
+****************** Fin code ******************
+
+
+****************** Code 336 ******************
+\catcode`@11
+\def\deftok#1#2{\let#1= #2\empty}% d\xE9finit le token #1 (\empty au cas o\xF9 #2 est vide)
+\deftok\sptoken{ }
+\def\ifnexttok#1#2#3{% lit les 3 arguments : #1=token #2=code vrai #3=code faux
+	\deftok\test at tok{#1}% stocke le token cherch\xE9
+	\def\true at code{#2}\def\false at code{#3}% et les codes \xE0 ex\xE9cuter
+	\ifnexttok at i% aller \xE0 la macro r\xE9cursive
+}
+\def\ifnexttok at i{%
+	\futurelet\nxttok\ifnexttok at ii% piocher le token d'apr\xE8s et aller \xE0 \ifnexttok at ii
+}
+\def\ifnexttok at ii{%
+	\ifx\nxttok\sptoken% si le prochain token est un espace
+		\def\donext{%
+			\afterassignment\ifnexttok at i% recommencer apr\xE8s
+			\let\nxttok= % apr\xE8s avoir absorb\xE9 cet espace
+		}%
+	\else
+		\ifx\nxttok\test at tok% si le prochain token est celui cherch\xE9
+			\let\donext\true at code% ex\xE9cuter le code vrai
+		\else
+			\let\donext\false at code% sinon code faux
+		\fi
+	\fi
+	\donext% faire l'action d\xE9cid\xE9e ci-dessus
+}
+\catcode`@12
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }W.\par
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }a.\par
+\ifnexttok *{je vais lire une \xE9toile : }{je ne vais pas lire une \xE9toile : } *.\par
+\ifnexttok *{je vais lire une \xE9toile : }{je ne vais pas lire une \xE9toile : }a.
+****************** Fin code ******************
+
+
+****************** Code 337 ******************
+\catcode`@11
+\newif\iftestspace \testspacefalse
+\def\deftok#1#2{\let#1= #2}\deftok\sptoken{ }
+\def\ifnexttok#1#2#3{% #1=token #2=code vrai #3=code faux
+	\let\test at tok= #1% stocke le token \xE0 tester
+	\def\true at code{#2}\def\false at code{#3}% et les codes \xE0 ex\xE9cuter
+	\iftestspace \def\ifnexttok at i{\futurelet\nxttok\ifnexttok at ii}%
+	\else        \def\ifnexttok at i{\futurelet\nxttok\ifnexttok at iii}%
+	\fi% apr\xE8s avoir d\xE9fini la macro r\xE9cursive selon le bool\xE9en,
+	\ifnexttok at i% l'ex\xE9cuter
+}
+\def\ifnexttok at ii{% macro "normale" qui ne teste pas les espaces
+	\ifx\nxttok\test at tok \expandafter\true at code% ex\xE9cuter le code vrai
+	\else                \expandafter\false at code% sinon code faux
+	\fi
+}
+\def\ifnexttok at iii{% macro qui ignore les espaces
+	\ifx\nxttok\sptoken% si le prochain token est un espace
+		\def\donext{%
+			\afterassignment\ifnexttok at i% lire le token d'apr\xE8s
+			\let\nxttok= % apr\xE8s avoir absorb\xE9 l'espace
+		}%
+	\else
+		\let\donext\ifnexttok at ii% sinon, faire le test "normal"
+	\fi
+	\donext% faire l'action d\xE9cid\xE9e ci-dessus
+}
+\catcode`@12
+\testspacefalse
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }W.\par
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : } W.\medbreak
+\testspacetrue
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }W.\par
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : } W.
+****************** Fin code ******************
+
+
+****************** Code 338 ******************
+\def\ifstarred#1{\ifnexttok*{\firstoftwo{#1}}}
+\catcode`\@11
+\def\teststar{\ifstarred{\teststar at bf}{\teststar at it}}
+\def\teststar at bf#1{{\bf#1}}
+\def\teststar at it#1{{\it#1\/}}
+\catcode`\@12
+
+Un essai \teststar{r\xE9ussi} et un essai \teststar*{\xE9toil\xE9} r\xE9ussi aussi.
+****************** Fin code ******************
+
+
+****************** Code 339 ******************
+\catcode`\@11
+\def\parsestop{\parsestop}% d\xE9finit la macro-quark se trouvant en fin de code
+\newtoks\code at toks% registre contenant le code lu
+\def\parseadd{\addtotoks\code at toks}
+\def\parse{%
+	\code at toks={}% initialise \code at toks \xE0 vide
+	\parse at i% et passe la main \xE0 \parse at i
+}
+\def\parse at i{\futurelet\nxttok\parse at ii}% lit le prochain token et va \xE0 \parse at ii
+\def\parse at ii{%
+	\ifxcase\nxttok
+		\parsestop\parsestop at i% si la fin va \xEAtre atteinte, aller \xE0 \parsestop at i
+		\sptoken\read at space% si un espace va \xEAtre lu, aller \xE0 \read at space
+		\bgroup\read at bracearg% si une accolade ouvrante  aller \xE0 \read at bracearg
+	\elseif
+		\testtoken% dans les autres cas, aller \xE0 \testtoken
+	\endif
+}
+
+\def\parsestop at i\parsestop{% la fin est atteinte : manger \parsestop
+	\the\code at toks% afficher le registre de tokens
+}
+\expandafter\def\expandafter\read at space\space{% manger un espace dans le code
+	\testtoken{ }% et aller \xE0 \testtoken
+}
+\def\read at bracearg#1{% l'argument entre accolades est lu
+	\parseadd{{#1}}% puis ajout\xE9 (entre accolades) tel quel \xE0 \code at toks
+	\parse at i% ensuite, lire le prochain token
+}
+\catcode`@12
+
+{\bf Exemple 1 :}
+\catcode`@11
+\def\testtoken#1{% macro qui teste le token
+	\ifxcase{#1}
+		a{\parseadd{e}}% remplacer a par e
+		e{\parseadd{i}}% e par i
+		i{\parseadd{o}}% i par o
+		o{\parseadd{u}}% o par u
+		u{\parseadd{y}}% u par y
+		y{\parseadd{a}}% y par a
+	\elseif
+		\parseadd{#1}% sinon, ajouter le token tel quel
+	\endif
+	\parse at i% aller lire le token suivant
+}%
+\catcode`@12
+\parse
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, corses ou grecques} assez inattendues.
+\parsestop\medbreak
+
+{\bf Exemple 2 :}
+\leavevmode \frboxsep=1pt 
+\catcode`@11
+\def\testtoken#1{%
+	\ifxcase{#1}% si #1 est un espace
+		{ }{\parseadd{\hskip 0.75em }}% ajouter un espace
+		\ {\parseadd{\hskip 0.75em }}
+	\elseif
+		\parseadd{\frbox{#1}}% sinon, l'encadrer
+	\endif
+	\parse at i}%
+\catcode`@12
+\parse Programmer en \TeX\ est facile\parsestop\medbreak
+
+{\bf Exemple 3 :}
+\catcode`@11
+\def\testtoken#1{%
+	\ifx a#1\parseadd{X}\else\parseadd{#1}\fi% remplace les "a" par des "X"
+	\parse at i
+}
+\catcode`@12
+\parse a\bgroup\bf braca\egroup dabra\parsestop
+****************** Fin code ******************
+
+
+****************** Code 340 ******************
+\catcode`\@11
+\def\ifbracefirst#1{%
+	\ifnum\catcode\expandafter\expandafter\expandafter
+		`\expandafter\firstto at nil\detokenize{#1W}\@nil=1 % tester si son catcode est 1
+		\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+}
+\catcode`\@12
+
+a) \ifbracefirst{123 456}{vrai}{faux}\qquad
+b) \ifbracefirst{\bgroup12\egroup3 456}{vrai}{faux}\qquad
+c) \ifbracefirst{{12}3 456}{vrai}{faux}\qquad
+d) \ifbracefirst{1{2}3 456}{vrai}{faux}\qquad
+\begingroup
+\catcode`[=1 \catcode`]=2 % les crochets deviennent des accolades
+e) \ifbracefirst[[]123 456][vrai][faux]
+\endgroup
+****************** Fin code ******************
+
+
+****************** Code 341 ******************
+\catcode`\@11
+\def\ifbracefirst#1{% teste si #1 commence par un token de catcode 1
+	\ifspacefirst{#1}% si #1 commence par un espace
+		{\secondoftwo}% renvoyer faux
+		{\ifnum\catcode\expandafter\expandafter\expandafter
+			`\expandafter\firstto at nil\detokenize{#1W}\@nil=1 % tester si son catcode est 1
+			\expandafter\firstoftwo
+		\else
+			\expandafter\secondoftwo
+		\fi
+		}%
+}
+
+\catcode`\@12
+a) \ifbracefirst{}{vrai}{faux}\qquad b) \ifbracefirst{ }{vrai}{faux}\qquad
+c) \ifbracefirst{ {}}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 342 ******************
+\catcode`\@11
+\def\parsestop at i\parsestop{% la fin va \xEAtre atteinte
+	\detokenize\expandafter{\the\code at toks}% afficher le contenu du registre
+}
+\def\read at bracearg{%
+	\read at bracearg@i\relax% ajoute un \relax avant de passer la main \xE0 \read at bracearg@i
+}
+\def\read at bracearg@i#1\parsestop{% #1 = tout jusqu'\xE0 \parsestop
+	\exparg\ifbracefirst{\gobone#1}% retire le \relax et teste si #1 commence par "{"
+		{\expandafter\read at bracearg@ii\gobone#1\parsestop}% si oui, aller \xE0 \readbrace at ii
+		{\expandafter\testtoken\gobone#1\parsestop}% sinon, aller \xE0 \testtoken
+}
+\def\read at bracearg@ii#1{% lit l'argument entre accolades
+	\parseadd{{#1}}% ajoute cet argument entre accolades
+	\parse at i% aller lire le token suivant
+}
+
+\def\testtoken#1{%
+	\parseadd{#1}% ajouter le token tel quel
+	\parse at i% aller lire le token suivant
+}
+\catcode`\@12
+\parse a\hbox\bgroup\bf braca\egroup {da}{}b{ra}\parsestop
+****************** Fin code ******************
+
+
+****************** Code 343 ******************
+\catcode`\@11
+\def\parsestop{\parsestop}% d\xE9finit le quark se trouvant en fin de code
+\newtoks\code at toks% alloue le registre contenant le code lu
+\def\parseadd#1{\code at toks\expandafter{\the\code at toks#1}}
+\newif\ifparse at group
+\def\parse{%
+	\code at toks{}% initialise le collecteur de tokens
+	\ifstarred% teste si la macro est \xE9toil\xE9e
+		{\parse at grouptrue\parse at i}% mettre le bool\xE9en \xE0 vrai
+		{\parse at groupfalse\parse at i}% sinon \xE0 faux
+}
+\def\parse at i{\futurelet\nxttok\parse at ii}% lit le prochain token
+                                        % et va \xE0 \parse at ii
+\def\parse at ii{%
+	\ifxcase\nxttok
+		\parsestop\parsestop at i% si la fin va \xEAtre atteinte, aller \xE0 \parsestop at i
+		\sptoken\read at space% si un espace va \xEAtre lu, aller \xE0 \read at space
+		\bgroup\read at bracearg% si une accolade ouvrante  aller \xE0 \read at bracearg
+	\elseif
+		\testtoken% dans les autres cas, aller \xE0 \testtoken
+	\endif
+}
+\def\parsestop at i\parsestop{% la fin est atteinte
+	\the\code at toks% afficher le registre de tokens
+}
+\expandafter\def\expandafter\read at space\space{% \read at space mange un espace dans le code
+	\testtoken{ }% et va \xE0 \testtoken
+}
+\def\read at bracearg{%
+	\read at bracearg@i\relax% ajoute un \relax avant de passer la main \xE0 \read at bracearg@i
+}
+\def\read at bracearg@i#1\parsestop{% l'argument tout jusqu'\xE0 \parsestop
+	\expsecond\ifbracefirst{\gobone#1}% retire le \relax et teste si #1 commence par "{"
+		{\expandafter\read at bracearg@ii\gobone#1\parsestop}% lire l'argument entre accolades
+		{\expandafter\testtoken\gobone#1\parsestop}% sinon, tester le token
+}
+\def\read at bracearg@ii#1{% l'argument entre accolades est lu
+	\ifparse at group\expandafter\firstoftwo\else\expandafter\secondoftwo\fi% si macro \xE9toil\xE9e
+		{\begingroup% ouvre un groupe pour parser l'int\xE9rieur de l'accolade
+			\def\parsestop at i\parsestop{% red\xE9finir localement \parsestop at i pour
+				\expandafter\endgroup% ne fermer le groupe qu'apr\xE8s avoir
+				\expandafter\parseadd% 1-d\xE9velopp\xE9 \xE0 l'ext\xE9rieur du groupe
+				\expandafter{\expandafter{\the\code at toks}}%
+				\parse at i% puis va lire le token suivant
+			}%
+			\parse*#1\parsestop% <- le \parsestop at i fermera le groupe semi-simple
+		}
+		{\parseadd{{#1}}% macro non \xE9toil\xE9e, on ajoute #1 tel quel entre accolades
+		\parse at i% puis va lire le token suivant
+		}%
+}
+\def\testtoken#1{% macro qui teste le token
+	\ifxcase{#1}
+		a{\parseadd{e}}
+		e{\parseadd{i}}
+		i{\parseadd{o}}
+		o{\parseadd{u}}
+		u{\parseadd{y}}
+		y{\parseadd{a}}
+	\elseif
+		\parseadd{#1}%
+	\endif
+	\parse at i% aller lire le token suivant
+}
+\catcode`@12
+\frboxsep=1pt
+a) \parse
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, \frbox{corses} ou grecques} assez inattendues.
+\parsestop\medbreak
+
+b) \parse*
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, \frbox{corses} ou grecques} assez inattendues.
+\parsestop
+****************** Fin code ******************
+
+
+****************** Code 344 ******************
+\catcode`\@11
+\def\parse{%
+	\code at toks{}% initialise le collecteur de tokens
+	\ifstarred
+		{\parse at grouptrue
+		\ifnexttok{ }% si un espace suit l'\xE9toile
+			{\afterassignment\parse at i% aller \xE0 \parse at i
+			\let\nxttok= }% apr\xE8s l'avoir mang\xE9
+			{\parse at i}% sinon, aller \xE0 \parse at i
+		}
+		{\parse at groupfalse
+		\parse at i
+		}%
+}
+\def\testtoken#1{% macro qui teste le token
+	\ifxcase{#1}
+		a{\parseadd{e}}e{\parseadd{i}}i{\parseadd{o}}o{\parseadd{u}}
+		u{\parseadd{y}}y{\parseadd{a}}
+	\elseif
+		\parseadd{#1}%
+	\endif
+	\parse at i% aller lire le token suivant
+}
+\catcode`@12
+\frboxsep=1pt
+a) \parse
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, \frbox{corses} ou grecques} assez inattendues.
+\parsestop\medbreak
+b) \parse*
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, \frbox{corses} ou grecques} assez inattendues.
+\parsestop
+****************** Fin code ******************
+
+
+****************** Code 345 ******************
+\catcode`\@11
+\def\grab at first#1#2{%
+	\ifx#1\empty\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{\let#2\empty% si #1 est vide, ne rien faire et assigner <vide> \xE0 #2
+		}% si #1 n'est pas vide
+		{\def\arg at b{#2}% stocke la macro #2 dans \arg at b
+		\exparg\ifbracefirst#1% si le 1er token de #1 est "{"
+			{\expandafter\grab at arg#1\@nil#1% aller lire l'argument avec \grab at arg
+			}
+			{% sinon, d\xE9velopper #1 avant de le regarder avec \futurelet :
+			\expandafter\futurelet\expandafter\nxttok\expandafter\test at nxttok#1\@nil#1%
+			% puis aller \xE0 \test at nxttok
+			}%
+		}%
+}
+\def\test at nxttok{% si le premier token de l'arg #1 de \grab at first est
+	\ifx\nxttok\sptoken% un espace
+		\expandafter\grab at spc% aller le lire avec \grab at spc
+	\else
+		\expandafter\grab at tok% sinon, lire le token avec \grab at tok
+	\fi
+}
+\def\grab at arg#1{% assigne l'argument de \grab at first (mis entre accolades)
+	\expandafter\def\arg at b{{#1}}% \xE0 #2
+	\assign at tonil\relax% puis, assigne le reste \xE0 #1 de \grab at first
+}
+\expandafter\def\expandafter\grab at spc\space{%
+	\expandafter\def\arg at b{ }% assigne un espace \xE0 #2 de \grab at first
+	\assign at tonil\relax% puis, assigne le reste \xE0 #1 de \grab at first
+}
+\def\grab at tok#1{%% assigne le premier token de l'arg #1 de \grab at first
+	\expandafter\def\arg at b{#1}% \xE0 la macro #2 de \grab at first
+	\assign at tonil\relax% puis, assigne le reste \xE0 #1 de \grab at first
+}
+% assigne tout ce qui reste \xE0 lire (moins le "\relax") \xE0 la macro
+% #1 de \grab at first
+\def\assign at tonil#1\@nil#2{\expsecond{\def#2}{\gobone#1}}
+\tt
+a) \def\foo{1 {2 3} 4}\grab at first\foo\bar
+   "\meaning\bar"\qquad"\meaning\foo"
+
+b) \def\foo{ 1 {2 3} 4}\grab at first\foo\bar
+   "\meaning\bar"\qquad"\meaning\foo""
+
+c) \def\foo{{1 2} 3 4}\grab at first\foo\bar
+   "\meaning\bar"\qquad"\meaning\foo"
+****************** Fin code ******************
+
+
+****************** Code 346 ******************
+\catcode`\@11
+\def\ifstartwith#1#2{% #1=<texte>  #2=<motif>
+	\ifempty{#2}
+		\firstoftwo% si <motif> est vide, renvoyer vrai
+		{\ifempty{#1}% si <code> est vide et <motif> non vide
+			\secondoftwo% renvoyer faux
+			{\def\startwith at code{#1}\def\startwith at pattern{#2}%
+			\ifstartwith at i% dans les autres cas, aller \xE0 \ifstartwith at i
+			}%
+		}%
+}
+\def\ifstartwith at i{%
+	\grab at first\startwith at code\first at code% extrait le premier "argument" de <texte>
+	\grab at first\startwith at pattern\first at pattern% et celui de <motif>
+	\ifx\first at code\first at pattern\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{% si les deux arguments \xE9largis sont \xE9gaux
+		\exparg\ifempty\startwith at pattern
+			\firstoftwo% et que <motif> ne contient plus rien => vrai
+			{\exparg\ifempty\startwith at code
+				\secondoftwo% si <texte> ne contient plus rien => faux
+				\ifstartwith at i% sinon poursuivre les tests
+			}%
+		}
+		\secondoftwo% si les deux argument \xE9largis sont diff\xE9rents, renvoyer faux
+}
+\catcode`\@12
+
+1) \ifstartwith{a b c}{a b}{oui}{non}\quad 2) \ifstartwith{a b}{a b c}{oui}{non}\quad
+3) \ifstartwith{ 123 }{ }{oui}{non}\quad   4) \ifstartwith{ 123 }{1}{oui}{non}\quad
+5) \ifstartwith{1{2} 3}{12}{oui}{non}\quad 6) \ifstartwith{1{2} 3}{1{2} }{oui}{non}\quad
+7) \ifstartwith{{} {}}{ }{oui}{non}\quad   8) \ifstartwith{{} {}}{{} }{oui}{non}\quad
+9) \ifstartwith{ {12} a}{ }{oui}{non}\quad10) \ifstartwith{ {12} a}{ {1}}{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 347 ******************
+\catcode`\@11
+\def\ifcontain#1#2{% #1 contient-il #2?
+	\def\main at arg{#1}\def\pattern at arg{#2}% stocke le <code> et le <motif>
+	\ifempty{#2}
+		\firstoftwo% si #2 est vide => vrai
+		{\ifempty{#1}
+			\secondoftwo% si #1 est vide et pas #2 => faux
+			\ifcontain at i% sinon, aller faire les tests
+		}%
+}
+\def\ifcontain at i{%
+	\exptwoargs\ifstartwith\main at arg\pattern at arg
+		\firstoftwo% si motif est au d\xE9but de code => vrai
+		{\exparg\ifempty\main at arg
+			\secondoftwo% sinon, si code est vide => faux
+			{\grab at first\main at arg\aux at arg% autrement, manger le 1er "argument" de code
+			\ifcontain at i% et recommencer
+			}%
+		}%
+}
+\catcode`\@12
+1) \ifcontain{abc def}{c }{oui}{non}\quad  2) \ifcontain{abc def}{cd}{oui}{non}\quad
+3) \ifcontain{12 34 5}{1 }{oui}{non}\quad  4) \ifcontain{12 34 5}{ }{oui}{non}\quad
+5) \ifcontain{a{b c}d}{b c}{oui}{non}\quad 6) \ifcontain{a{b c}d}{{b c}}{oui}{non}\quad
+7) \ifcontain{{} {}}{ }{oui}{non}\quad     8) \ifcontain{{} {}}{{}}{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 348 ******************
+\catcode`@11
+\newif\ifin at group
+\def\ifcontain{%
+	\ifstarred
+		{\in at groupfalse\ifcontain at i\ifcontain at star}%
+		{\ifcontain at i\ifcontain at nostar}}
+
+\def\ifcontain at i#1#2#3{% #1 = macro \xE0 appeler selon \xE9toile ou pas. #2 = code. #3 = motif
+	\def\main at arg{#2}\def\pattern at arg{#3}%
+	\ifempty{#3}
+		\firstoftwo
+		{\ifempty{#2}
+			\secondoftwo
+			#1% aller \xE0 \ifcontain at star ou \ifcontain at nostar
+		}%
+}
+\def\ifcontain at nostar{%
+	\exptwoargs\ifstartwith\main at arg\pattern at arg
+		\firstoftwo% si motif est au d\xE9but de code => vrai
+		{\exparg\ifempty\main at arg
+			\secondoftwo% sinon, si code est vide => faux
+			{\grab at first\main at arg\aux at arg% autrement, manger le 1er "argument" de code
+			\ifcontain at nostar% et recommencer
+			}%
+		}%
+}
+\def\ifcontain at star{%
+	\expandafter\ifbracefirst\expandafter{\main at arg}% si code commence par "{"
+		{\grab at first\main at arg\aux at arg% enlever {<argument>} de main at arg
+		\begingroup% ouvrir un groupe
+			\in at grouptrue% mettre le bool\xE9en \xE0 vrai
+			\expandafter\def\expandafter\main at arg\aux at arg% assigner "argument" \xE0 \main at arg
+			\ifcontain at star% et recommencer avec ce nouveau \main at arg
+		}% si code ne commence pas par "{"
+		{\exptwoargs\ifstartwith\main at arg\pattern at arg% si motif est au d\xE9but de code
+			\return at true% renvoyer vrai
+			{\expandafter\ifempty\expandafter{\main at arg}% si code est vide
+				{\ifin at group% et que l'on est dans un groupe
+					\endgroup \expandafter\ifcontain at star% en sortir et recommencer
+				\else% si on n'est pas dans un groupe, le code a \xE9t\xE9 parcouru
+					\expandafter\secondoftwo% sans trouver <motif> => renvoyer faux
+				\fi
+				}% si code n'est pas vide
+				{\grab at first\main at arg\startwith at code% manger le 1er "argument" de code
+				\ifcontain at star% et recommencer
+				}%
+			}%
+		}%
+}
+\def\return at true{%
+	\ifin at group% tant qu'on est dans un groupe
+		\endgroup \expandafter\return at true% en sortir et recommencer
+	\else
+		\expandafter\firstoftwo% sinon, renvoyer vrai
+	\fi
+}
+\catcode`@12
+1) \ifcontain{ab {c d}ef}{c}{oui}{non}\quad 2) \ifcontain*{ab {c d}ef}{c}{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 349 ******************
+\catcode`@11
+\newtoks\subst at toks% registre de tokens pour stocker le <texte> modifi\xE9
+\def\substitute{%
+	\def\substitute at end{\the\subst at toks}% macro ex\xE9cut\xE9e \xE0 la fin
+	\ifstarred
+		{\let\recurse at macro\substitute at star  \substitute at i}%
+		{\let\recurse at macro\substitute at nostar\substitute at i}%
+}
+\def\substitute at i#1#2#3#4{% #1=macro \xE0 appeler selon \xE9toile ou pas.
+                          % #2=<texte> #3=<motif>  #4=<motif de substi>
+	\def\code at arg{#2}\def\pattern at arg{#3}\def\subst at arg{#4}%
+	\subst at toks={}% initialiser le collecteur \xE0 vide
+	#1% aller \xE0 \substitute at star ou \substitute at nostar
+}
+\def\substitute at nostar{%
+	\exptwoargs\ifstartwith\code at arg\pattern at arg% si le <texte> commence par <motif>
+		{\eaddtotoks\subst at toks\subst at arg% ajouter <motif subst>
+		\grab at first\code at arg\aux at code% manger le 1er "argument" de <texte>
+		\substitute at nostar% et recommencer
+		}
+		{\expandafter\ifempty\expandafter{\code at arg}%
+			{\substitute at end% sinon, si <texte> est vide => afficher le registre de tokens
+			}
+			{\grab at first\code at arg\aux at arg% autrement, manger le 1er "argument" de <texte>
+			\eaddtotoks\subst at toks\aux at arg% et l'ajouter au registre de tokens
+			\substitute at nostar% et recommencer
+			}%
+		}%
+}
+\def\substitute at star{%
+	\expandafter\ifbracefirst\expandafter{\code at arg}% si <texte> commence par "{"
+		{\grab at first\code at arg\aux at arg% enlever {<argument>} de \code at arg
+		\begingroup% ouvrir un groupe
+			\def\substitute at end{% modifier localement la macro ex\xE9cut\xE9e \xE0 la fin
+				\expandafter\endgroup\expandafter% avant de fermer le groupe
+				\addtotoks\expandafter\subst at toks\expandafter% ajouter au registre hors du groupe
+					{\expandafter{\the\subst at toks}}% ce qui est collect\xE9 localement, mis entre {}
+			\substitute at star% puis recommencer
+			}%
+			\subst at toks{}% initialiser \xE0 vide
+			\expandafter\def\expandafter\code at arg\aux at arg% % assigner "argument" au <texte>
+			\substitute at star% et recommencer avec ce nouveau \code at arg
+		}% si code ne commence pas par "{"
+		{\exptwoargs\ifstartwith\code at arg\pattern at arg% si <motif> est au d\xE9but de <texte>
+			{\eaddtotoks\subst at toks\subst at arg% ajouter <motif subst>
+			\grab at first\code at arg\aux at code% manger le 1er "argument" de <texte>
+			\substitute at star% et recommencer
+			}
+			{\expandafter\ifempty\expandafter{\code at arg}% si <texte> est vide
+				{\substitute at end% aller \xE0 la macro de fin
+				}% si <texte> n'est pas vide
+				{\grab at first\code at arg\aux at code% manger le 1er "argument" de <texte>
+				\eaddtotoks\subst at toks\aux at code% et l'ajouter au registre
+				\substitute at star% et recommencer
+				}%
+			}%
+		}%
+}
+\catcode`@12
+1) \substitute{ab{\bf racada}bra}{a}{W}\qquad
+2) \substitute*{ab{\bf racada}bra}{a}{W}\qquad
+3) \substitute{12\frbox{\bf 34}56}{\bf}{\it}\qquad
+4) \substitute*{12\frbox{\bf 34}56}{\bf}{\it}
+****************** Fin code ******************
+
+
+****************** Code 350 ******************
+\catcode`@11
+\newtoks\subst at toks% registre de tokens pour stocker le <texte> modifi\xE9
+\def\substitute{%
+	\def\substitute at end{\the\subst at toks}% macro ex\xE9cut\xE9e \xE0 la fin
+	\ifstarred
+		{\let\recurse at macro\substitute at star  \substitute at i}%
+		{\let\recurse at macro\substitute at nostar\substitute at i}%
+}
+\def\substitute at i#1#2#3{% #1=<texte> #2=<motif> #3=<motif de substi>
+	\def\code at arg{#1}\def\pattern at arg{#2}\def\subst at arg{#3}%
+	\subst at toks={}% initialiser \xE0 vide
+	\recurse at macro% aller \xE0 \substitute at star ou \substitute at nostar
+}
+\def\substitute at nostar{%
+	\exptwoargs\ifstartwith\code at arg\pattern at arg% si le <texte> commence par <motif>
+		{\eaddtotoks\subst at toks\subst at arg% ajouter <motif subst>
+		\grab at first\code at arg\aux at code% manger le 1er "argument" de <texte>
+		\recurse at macro% et recommencer
+		}
+		{\expandafter\ifempty\expandafter{\code at arg}%
+			\substitute at end% sinon, si <texte> est vide => afficher le registre de tokens
+			{\grab at first\code at arg\aux at arg% autrement, manger le 1er "argument" de <texte>
+			\eaddtotoks\subst at toks\aux at arg% et l'ajouter au registre de tokens
+			\recurse at macro% et recommencer
+			}%
+		}%
+}
+\def\substitute at star{%
+	\expandafter\ifbracefirst\expandafter{\code at arg}% si <texte> commence par "{"
+		{\grab at first\code at arg\aux at arg% enlever {<argument>} de \code at arg
+		\begingroup% ouvrir un groupe
+			\def\substitute at end{% modifier localement la macro ex\xE9cut\xE9e \xE0 la fin
+				\expandafter\endgroup\expandafter% avant de fermer le groupe
+				\addtotoks\expandafter\subst at toks\expandafter% ajouter au registre hors du groupe
+					{\expandafter{\the\subst at toks}}% ce qui est collect\xE9 localement, mis entre {}
+				\recurse at macro% puis recommencer
+			}%
+			\subst at toks{}% initialiser \xE0 vide
+			\expandafter\def\expandafter\code at arg\aux at arg% % assigner "argument" au <texte>
+			\recurse at macro% et recommencer avec ce nouveau \code at arg
+		}% si <texte> ne commence pas par "{" :
+		\substitute at nostar% ex\xE9cuter macro non \xE9toil\xE9e pour une seule it\xE9ration
+}
+\def\substitutetocs{%
+	\ifstarred
+		{\let\recurse at macro\substitute at star  \substitutetocs at i}%
+		{\let\recurse at macro\substitute at nostar\substitutetocs at i}%
+}
+\def\substitutetocs at i#1#2#3#4{% #1=<texte> #2=<motif> #3=<motif de substi> #4=\<macro>
+	\def\substitute at end{\edef#4{\the\subst at toks}}% macro ex\xE9cut\xE9e \xE0 la fin
+	\substitute at i{#1}{#2}{#3}% continuer comme avec \substitute
+}
+\catcode`@12
+\frboxsep=1pt
+1) \substitute{ab{\bf racada}bra}{a}{W}\qquad
+2) \substitute*{ab{\bf racada}bra}{a}{W}\qquad
+3) \substitute{12\frbox{\bf 34}56}{\bf}{\it}\qquad
+4) \substitute*{12\frbox{\bf 34}56}{\bf}{\it}
+\medbreak
+
+1) \substitutetocs{ab{\bf racada}bra}{a}{W}\foo       \meaning\foo\par
+2) \substitutetocs*{ab{\bf racada}bra}{a}{W}\foo      \meaning\foo\par
+3) \substitutetocs{12\frbox{\bf 34}56}{\bf}{\it}\foo  \meaning\foo\par
+4) \substitutetocs*{12\frbox{\bf 34}56}{\bf}{\it}\foo \meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 351 ******************
+\catcode`@11
+\def\vecteur{%
+	\ifnexttok[% si la macro est suivie d'un crochet
+		\vecteur at i% aller \xE0 la macro \xE0 arguments d\xE9limit\xE9s
+		{\vecteur at i[1]}% sinon, ajouter l'argument optionnel par d\xE9faut entre crochets
+}
+\def\vecteur at i[#1]#2{% #1=arg optionnel  #2=arg obligatoire
+	$(x_{#1},\ldots,x_{#2})$
+}
+\catcode`@12
+1) \vecteur{n}\qquad 2) \vecteur[0]{k}\qquad 3) \vecteur[i]j \qquad4) \vecteur[]n
+****************** Fin code ******************
+
+
+****************** Code 352 ******************
+\catcode`@11
+\def\forcemath#1{% compose #1 en mode math, quel que soit le mode en cours
+	\ifmmode\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{#1}{$#1$}%
+}
+\def\vecteur{%
+	\ifnexttok[% si la macro est suivie d'un crochet
+		\vecteur at i% aller \xE0 la macro \xE0 arguments d\xE9limit\xE9s
+		{\vecteur at i[1]}% sinon, ajouter l'argument optionnel par d\xE9faut entre crochets
+}
+\def\vecteur at i[#1]{%
+	\ifnexttok(% si une parenth\xE8se vient ensuite
+		{\vecteur at ii[#1]}% aller \xE0 la macro \xE0 argument d\xE9limit\xE9s
+		{\vecteur at ii[#1](x)}% sinon, rajouter "x" comme argument optionnel
+}
+\def\vecteur at ii[#1](#2)#3{% #1 et #2=arg optionnel  #3=arg obligatoire
+	\forcemath{({#2}_{#1},\ldots,{#2}_{#3})}%
+}
+\catcode`@12
+1) \vecteur{n}\qquad 2) \vecteur[0]{k}\qquad
+3) \vecteur[i](y)j \qquad4) \vecteur[](\alpha)n
+****************** Fin code ******************
+
+
+****************** Code 353 ******************
+\catcode`@11
+\def\vecteur{%
+	\ifnexttok[% si la macro est suivie d'un crochet
+		\vecteur at bracket% lire cet argument entre crochet
+		{\ifnexttok(% sinon, si elle est suivie d'une parenth\xE8se
+			\vecteur at paren % lire cet argument entre parenth\xE8ses
+			{\vecteur at i[1](x)}% sinon, transmettre les arguments par d\xE9faut
+		}%
+}
+\def\vecteur at bracket[#1]{%
+	\ifnexttok(% s'il y a une parenth\xE8se apr\xE8s
+		{\vecteur at i[#1]}% lire la parenth\xE8se
+		{\vecteur at i[#1](x)}% sinon, donne "x" comme argument par d\xE9faut
+}
+\def\vecteur at paren(#1){%
+	\ifnexttok[% si le caract\xE8re suivant est un crochet
+		{\vecteur at ii(#1)}% lire l'argument entre crochets
+		{\vecteur at ii(#1)[1]}% sinon, donner "1" comme argument par d\xE9faut
+}
+\def\vecteur at i[#1](#2)#3{\forcemath{({#2}_{#1},\ldots,{#2}_{#3})}}
+\def\vecteur at ii(#1)[#2]{\vecteur at i[#2](#1)}% met les arg optionnels dans l'ordre
+\catcode`@12
+1) \vecteur{n}\qquad 2) \vecteur[i](y){j}\qquad 3) \vecteur(y)[i]{j}\qquad
+4) \vecteur[0]{k}\qquad 5) \vecteur(\alpha){n}
+****************** Fin code ******************
+
+
+****************** Code 354 ******************
+\catcode`\@11
+\def\foo#1{% #1 -> lit le premier argument obligatoire
+	\ifnexttok[% si le token suivant est un crochet
+		{\foo at i{#1}}% aller \xE0 \foo at i qui va lire cet argument
+		{\foo at i{#1}[xxx]}% sinon, transmettre [xxx] \xE0 foo at i
+}
+
+\def\foo at i#1[#2]#3#4{% lit l'arg obligatoire + arg optionnel + 2 arg obligatoires
+	\ifnexttok[
+		{\foo at ii{#1}[#2]{#3}{#4}}%
+		{\foo at ii{#1}[#2]{#3}{#4}[y]}%
+}
+
+\def\foo at ii#1[#2]#3#4[#5]#6{% lit tous les arguments
+	1="#1" 2="#2" 3="#3" 4="#4" 5="#5" 6="#6"%
+}
+
+\catcode`\@12
+1) \foo{arg1}{arg2}{arg3}{arg4}\par
+2) \foo{arg1}[OPT\_A]{arg2}{arg3}{arg4}\par
+3) \foo{arg1}{arg2}{arg3}[OPT\_B]{arg4}\par
+4) \foo{arg1}[OPT\_A]{arg2}{arg3}[OPT\_B]{arg4}\medbreak
+****************** Fin code ******************
+
+
+****************** Code 355 ******************
+\catcode`\@11
+\newcount\macro at cnt% num\xE9ro \xE0 mettre dans le nom des sous macros
+\newcount\arg at cnt% compte le nombre d'arguments
+\newtoks\param at text% texte de param\xE8tre des macros sous forme "#x" et/ou "[#x]"
+\newtoks\arg at text% arguments sous forme "{#x}" et/ou "[#x]"
+
+\def\newmacro#1{%
+	% \macro at name construit le <nom> de la macro et \xE9ventuellement "@[<chiffre romain>]"
+	\def\macro at name##1{\expandafter\gobone\string#1\ifnum##1>0 @[\romannumeral##1]\fi}%
+	\macro at cnt=0 \arg at cnt=0 % initialise les compteurs
+	\param at text{}\arg at text{}% vide les registres de texte de param\xE8tre et d'argument
+	\newmacro at i% va voir le prochain token
+}
+
+\def\newmacro at i{\futurelet\nxttok\newmacro at ii}% met le prochain token dans \nxttok...
+% ...puis va \xE0 la macro :
+\def\newmacro at ii{%
+	\ifxcase\nxttok
+		[\newmacro at optarg% si le prochain token est un crochet aller \xE0 \newmacro at optarg
+		\bgroup% si c'est un accolade ouvrante
+			% le texte de param\xE8tre est fini et il faut d\xE9finir la macro
+			{\defname{\macro at name\macro at cnt\expandafter}%
+			\the\param at text}% <- le {<code>} est juste apr\xE8s, il n'est pas encore lu
+	\elseif% sinon, c'est donc un chiffre
+			\newmacro at arg% aller \xE0 \newmacro at arg
+	\endif
+}
+
+\def\newmacro at optarg[#1]{% lit la valeur par d\xE9faut de l'argument optionnel
+	% D\xE9finit la macro \<nom>@[<nbre>] qui lit tous les arguments (optionnels ou pas)
+	% jusqu'alors d\xE9finis \xE0 l'aide de \param at text. Puis, cette macro testera si le prochain
+	% token est un crochet
+	\expandafter\edef\csname\macro at name\macro at cnt\expandafter\endcsname\the\param at text{%
+		\noexpand\ifnexttok[%
+			% si oui : la macro \<nom>@<nbr+1> le lira
+			{\expandafter\noexpand\csname\macro at name{\numexpr\macro at cnt+1}\expandafter\endcsname
+			\the\arg at text}%
+			% si non : transmettre \xE0 \<nom>@<nbr+1> l'argument optionnel par d\xE9faut lu
+			{\expandafter\noexpand\csname\macro at name{\numexpr\macro at cnt+1}\expandafter\endcsname
+			\the\arg at text[\unexpanded{#1}]}%
+	}%
+	\advance\arg at cnt 1 % incr\xE9menter le num\xE9ro d'argument
+	% pour ajouter "[#<x>]" \xE0 \param at text et \xE0 \arg at text
+	\eaddtotoks\param at text{\expandafter[\expandafter##\number\arg at cnt]}%
+	\eaddtotoks\arg at text  {\expandafter[\expandafter##\number\arg at cnt]}%
+	\advance\macro at cnt 1 % incr\xE9menter le num\xE9ro de nom de macro
+	\newmacro at i% va voir le token suivant
+}
+
+\def\newmacro at arg#1{% #1=nombre d'arguments obligatoires \xE0 ajouter
+	% boucle qui ajoute "#<x>#<x+1>etc" dans \param at text
+	% et "{#<x>}{#<x+1>}etc" dans \arg at text
+	\ifnum#1>\z@ % tant qu'on n'a pas ajout\xE9 le nombre de #x n\xE9cessaire
+		\advance\arg at cnt 1 % incr\xE9menter le num\xE9ro d'argument
+		% pour ajouter #x \xE0 \param at text et {#x} \xE0 \arg at text
+		\eaddtotoks\param at text{\expandafter##\number\arg at cnt}%
+		\eaddtotoks\arg at text  {\expandafter{\expandafter##\number\arg at cnt}}%
+		\expandafter\newmacro at arg\expandafter{\number\numexpr#1-1\expandafter}% boucler
+	\else% si les arguments sont tous ajout\xE9s
+		\expandafter\newmacro at i% lire le token suivant
+	\fi
+}
+\catcode`\@12
+\newmacro\foo 1[xxx]2[y]1{1="#1" 2="#2" 3="#3" 4="#4" 5="#5" 6="#6"}
+a) \foo{arg1}{arg2}{arg3}{arg4}\par
+b) \foo{arg1}[OPT\_A]{arg2}{arg3}{arg4}\par
+c) \foo{arg1}{arg2}{arg3}[OPT\_B]{arg4}\par
+d) \foo{arg1}[OPT\_A]{arg2}{arg3}[OPT\_B]{arg4}\medbreak
+
+\meaning\foo\par
+\expandafter\meaning\csname foo@[i]\endcsname\par
+\expandafter\meaning\csname foo@[ii]\endcsname
+****************** Fin code ******************
+
+
+****************** Code 356 ******************
+\newmacro\framebox[ULRD]1{% #1 = ULRD (Up, Down, Right, Left)
+% ne pas changer le mode H ou V en cours
+	\hbox{% enferme dans une \hbox
+		\uppercase{\ifin{#1}L}{\vrule width\frboxrule}{}% r\xE9glure gauche
+		\vtop{%
+			\vbox{% 1er \xE9l\xE9ment de la \vtop
+				\uppercase{\ifin{#1}U}{% si la r\xE9glure sup doit \xEAtre trac\xE9e
+					\hrule height\frboxrule% r\xE9glure sup\xE9rieure
+					\kern\frboxsep% espace haut
+					}
+					{}%
+				\hbox{%
+					\uppercase{\ifin{#1}L}{\kern\frboxsep}{}% espace gauche
+					#2% contenu
+					\uppercase{\ifin{#1}R}{\kern\frboxsep}{}% espace droite
+					}%
+			}% puis autres \xE9l\xE9ments de la \vtop, sous la ligne de base
+			\uppercase{\ifin{#1}D}{%
+				\kern\frboxsep% espace bas
+				\hrule height\frboxrule% r\xE9glure inf\xE9rieure
+				}%
+				{}%
+		}%
+		\uppercase{\ifin{#1}R}{\vrule width\frboxrule}{}% r\xE9glure droite
+	}%
+}
+\frboxsep=1pt 
+Boite \framebox{enti\xE8re}, \framebox[ud]{Up down}, \framebox[LR]{Left Right},
+\framebox[LU]{Left Up} et \framebox[rd]{Right Down}.
+****************** Fin code ******************
+
+
+****************** Code 357 ******************
+\catcode`\@11
+\newtoks\eargs at toks
+\newtoks\eargs at temptoks
+\def\eargs[#1]#2{% #1=liste des d\xE9veloppements  #2=macro
+	\eargs at toks{#2}% mettre la macro dans le collecteur de tokens
+	\expandafter\eargs at i\detokenize{#1}\@nil% appeler \eargs at i avec
+	                                        % la liste des developpements
+}
+
+\def\eargs at i#1\@nil{% #1=liste des n-d\xE9veloppements restant
+	\ifempty{#1}% s'il n' y plus de n-d\xE9veloppements
+		{\the\eargs at toks}% ex\xE9cuter la macro et ses arguments d\xE9velopp\xE9s
+		{\eargs at ii#1\@nil}% sinon appeller la macro qui lit un argument
+}
+
+% #1=n-d\xE9veloppement actuel  #2=liste des n-d\xE9veloppements restants   #3=argument lu
+\def\eargs at ii#1#2\@nil#3{%
+	\if+#1% si #1="+", un \edef est demand\xE9 pour cet argument
+		\edef\eargs at tempmacro{{#3}}% le stocker dans une macro temporaire
+	\else% sinon
+		\eargs at temptoks={#3}% stocker l'argument dans un registre temporaire
+		\for\eargs at loop = 1 to #1\do 1 % faire #1 fois :
+			{\eargs at temptoks=% 1-d\xE9velopper le 1er token du registre temporaire
+				\expandafter\expandafter\expandafter{\the\eargs at temptoks}%
+			}% puis le stocker dans la macro temporaire
+		\edef\eargs at tempmacro{{\the\eargs at temptoks}}%
+	\fi
+	\eaddtotoks\eargs at toks\eargs at tempmacro% ajouter le contenu de la macro au collecteur
+	\eargs at i#2\@nil% appeler \eargs at i avec les n-d\xE9veloppements restants
+}
+\catcode`\@12
+\def\foo#1#2#3#4#5{\detokenize{1="#1" 2="#2" 3="#3" 4="#4" 5="#5"}}
+\def\aaa{\bbb}\def\bbb{\ccc}\def\ccc{Bonjour}
+
+\eargs[0123+]\foo{\aaa\bbb}{\aaa\bbb}{\aaa\bbb}{\aaa\bbb}{\aaa\bbb}.
+****************** Fin code ******************
+
+
+****************** Code 358 ******************
+\catcode`\@11
+\def\detectmark#1{% #1 est le marqueur
+	\begingroup
+		\catcode`#1=13 % rendra #1 actif apr\xE8s la macro
+		\begingroup% pour les besoins du \lccode
+			\lccode`\~=`#1 % transforme "~" en " #1 actif"
+			\lowercase{\endgroup\def~##1~}{\markeffect{##1}}%
+		\detectmark at i
+}
+\def\detectmark at i#1{%
+		#1% ex\xE9cute le code
+	\endgroup% ferme le groupe, le marqueur perd son catcode actif
+}
+\catcode`\@12
+a) \def\markeffect#1{{\bf #1}}% met en gras
+\detectmark+{Un +argument+ o\xF9 les +marqueurs+ sont d\xE9tect\xE9s}
+\medskip
+
+b) \def\markeffect#1{% met dans une boite
+	\begingroup
+		\frboxsep=1pt % modifie l'espacement entre texte et encadrement
+		\frbox{\strut#1}% encadre
+	\endgroup
+}
+\detectmark|{Un |argument| o\xF9 les |marqueurs| sont d\xE9tect\xE9s}
+\medskip
+
+c) \def\markeffect#1{$\vcenter{\hbox{#1}\hbox{#1}}$}% superpose 2 fois
+\detectmark`{Un `argument` o\xF9 les `marqueurs` sont d\xE9tect\xE9s}
+****************** Fin code ******************
+
+
+****************** Code 359 ******************
+\catcode`\@11
+\def\detectmark#1{%
+	\begingroup
+		\catcode`#1=13 % rendra #1 actif apr\xE8s la macro
+		\begingroup% pour les besoins du \lccode
+			\lccode`\~=`#1 % transforme "~" en " #1 actif"
+			\lowercase{\endgroup\def~##1~}{\markeffect{##1}}%%
+		\detectmark at i
+}
+\def\detectmark at i#1{%
+		#1% lit le code
+	\endgroup% ferme le groupe, le marqueur perd son catcode actif
+}
+\catcode`\@12
+\def\markeffect#1{{\bf #1}}% met en gras
+\frbox{\detectmark+{Un +argument+ o\xF9 les +marqueurs+ sont d\xE9tect\xE9s}}
+****************** Fin code ******************
+
+
+****************** Code 360 ******************
+\catcode`\@11
+\newtoks\alter at toks% collecteur de tokens
+
+\def\alter#1#2{% #1= d\xE9limiteur  #2 = macro \xE0 alt\xE9rer
+	\let\alter at macro#2% sauvegarde la macro
+	\edef\alter at restorecatcode{% restaurera le catcode de #1
+		\catcode`\noexpand#1=\the\catcode`#1 }%
+	\edef\alter at tmp{\let\noexpand\alter at markertoks= \string#1}%
+	\alter at tmp% et sauvegarder le d\xE9limiteur apr\xE8s avoir mis son catcode \xE0 12
+	\edef\alter at tmp{\def\noexpand\alter at readlitterate@i\string#1####1\string#1}%
+	% d\xE9veloppe les \string#1 pour que les arguments d\xE9limit\xE9s aient
+	% des d\xE9limiteurs de catcode 12
+	\alter at tmp{% <- comme si on \xE9crivait "\def\alter at readlitterate@i#1##1#1"
+		\endgroup% apr\xE8s avoir lu ##1 (tokens rendus inoffensifs), fermer le groupe
+		\addtotoks\alter at toks{{\tt##1}}% ajouter ces tokens
+		\alter at i% et aller lire le prochain token
+	}%
+	\alter at toks{}% initialise le collecteur de tokens
+	\afterassignment\alter at i% aller lire le premier token apr\xE8s avoir
+	\let\alter at tmptok= % mang\xE9 l'accolade ouvrante de l'<argument> qui suit
+}
+
+\def\alter at i{% lit le prochain token et va \xE0 \alter at ii
+	\futurelet\alter at nxttok\alter at ii}%
+
+\def\alter at ii{% teste le token qui doit \xEAtre lu
+	\ifxcase\alter at nxttok% si le token \xE0 lire est
+		\egroup           \alter at stop% "}" : aller \xE0 \alterstop at i
+		\sptoken          \alter at readspc% " " : aller \xE0 \alter at readspc
+		\bgroup           \alter at readarg% "{" : aller \xE0 \alter at readarg
+		\alter at markertoks \alter at readlitterate% "<delimiteur>" : aller \xE0 \alter at readlitterate
+	\elseif
+		\alter at readtok% dans les autres cas, aller \xE0 \alter at readtok
+	\endif
+}
+
+\def\alter at readlitterate{% le prochain token est le d\xE9limiteur
+	\begingroup% ouvrir un groupe
+	\for\alter at tmp=0to255\do{\catcode\alter at tmp=12 }%
+	% mettre tous les catcodes \xE0 12
+	\defactive{ }{\ }% sauf l'espace rendu actif
+	\doforeach\alter at tmp\in{<,>,-,`,{,},'}% pour chaque motif de ligature
+			{\unless\if\alter at tmp\alter at markertoks% s'il est diff\xE9rent du d\xE9limiteur
+				% le rendre actif pour \xE9viter la ligature
+				\expandafter\alter at defligchar\alter at tmp
+			\fi
+			}%
+	\alter at readlitterate@i% puis aller \xE0 \alter at readlitterate@i...
+	% ...qui a \xE9t\xE9 d\xE9finie dans \alter
+}
+
+\def\alter at defligchar#1{% d\xE9finit le caract\xE8re pour ne pas provoquer de ligature
+	\defactive#1{\string#1{}}%
+}
+
+\expandafter\def\expandafter\alter at readspc\space{% mange un espace dans le code
+	\addtotoks\alter at toks{ }% ajoute l'espace
+	\alter at i% puis lire le token suivant
+}
+
+\def\alter at readarg{% le token qui suit est "{"
+	\begingroup% ouvrir un groupe
+	\def\alter at stop@ii{% et modifier localement la macro appel\xE9e \xE0 la toute fin,
+	% apr\xE8s que l'accolade fermante ait \xE9t\xE9 mang\xE9e (par \alterstop at i)
+		\expandafter\endgroup% retarder la fermeture de groupe ouvert ci-dessus
+		\expandafter\addtotoks\expandafter\alter at toks\expandafter
+			{\expandafter{\the\alter at toks}}%
+		% pour ajouter hors du groupe ce qui a \xE9t\xE9 collect\xE9 \xE0 l'int\xE9rieur,
+		% le tout mis entre accolades
+		\alter at i% puis, lire le token suivant
+	}%
+	\alter at toks{}% au d\xE9but du groupe, initialiser le collecteur
+	\afterassignment\alter at i% aller lire le prochain token apr\xE8s
+	\let\alter at tmptok= % avoir mang\xE9 l'accolade ouvrante
+}
+
+\def\alter at readtok#1{% le prochain token ne demande pas une action sp\xE9ciale
+	\addtotoks\alter at toks{#1}% l'ajouter au collecteur
+	\alter at i% et aller lire le token suivant
+}
+
+\def\alter at stop{% le token \xE0 lire est "}"
+	\afterassignment\alter at stop@ii% aller \xE0 \alter at stop@ii apr\xE8s
+	\let\alter at tmptok= % avoir mang\xE9 l'accolade fermante
+}
+
+\def\alter at stop@ii{% donner \xE0 la \<macro> tout ce qui a \xE9t\xE9 r\xE9colt\xE9
+	\expandafter\alter at macro\expandafter{\the\alter at toks}%
+	\alter at restorecatcode% puis restaure le catcode du d\xE9limiteur
+}
+\catcode`@12
+
+\frboxsep=1pt 
+\alter|\frbox{Texte normal - |#& }| - texte normal - |_^ ##| - texte normal}
+\alter=\frbox{La macro =\alter= autorise du verbatim dans
+des commandes imbriqu\xE9es \frbox{comme ici =\alter=}.}
+****************** Fin code ******************
+
+
+****************** Code 361 ******************
+\def\hello#1#2{Bonjour #1 et  #2 !}
+\hello{foo}{bar}\par
+\alter|\identity{\hello{macro |{{{\foo|}{macro |\bar}|}}
+****************** Fin code ******************
+
+
+****************** Code 362 ******************
+\def\retokenize#1{%
+	\immediate\openout\wtest=retokenize.tex % ouvre le fichier
+	\immediate\write\wtest{\unexpanded{#1}}%  y \xE9crit l'argument
+	\immediate\closeout\wtest% ferme le fichier
+	\input retokenize.tex % lit le fichier selon les catcodes en vigueur
+	\unskip% mange l'espace pr\xE9c\xE9demment ajout\xE9 qui provient de la fin du fichier
+}
+\frboxsep=1pt
+1) \frbox{Programmer en \catcode`\~=12 \TeX{} est~facile et~utile.}\par
+2) \frbox{Programmer en \retokenize{\catcode`\~=12 \TeX{} est~facile} et~utile.}\par
+3) \frbox{Programmer en \catcode`\~=12 \retokenize{\TeX{} est~facile} et~utile.}
+****************** Fin code ******************
+
+
+****************** Code 363 ******************
+\frboxsep=1pt 
+1) \frbox{Programmer \retokenize{\litterate|en \TeX {} est |}facile et utile.}\par
+2) \frbox{Programmer \retokenize{\litterate|en    \TeX{} est |}facile et utile.}
+****************** Fin code ******************
+
+
+****************** Code 364 ******************
+\frboxsep=1pt 
+1) \frbox{Programmer en \catcode`\~=12 \TeX{} est~facile et~utile.}\par
+2) \frbox{Programmer en \scantokens{\catcode`\~=12 \TeX{} est~facile} et~utile.}\par
+3) \frbox{Programmer en \catcode`\~=12 \scantokens{\TeX{} est~facile} et~utile.}\par
+4) \frbox{Programmer \scantokens{\litterate|en \TeX {} est facile|} et utile.}\par
+5) \frbox{Programmer \scantokens{\litterate|en    \TeX{} est facile|} et utile.}
+****************** Fin code ******************
+
+
+****************** Code 365 ******************
+\scantokens{a}b
+****************** Fin code ******************
+
+
+****************** Code 366 ******************
+\begingroup\endlinechar=-1 \scantokens{a}b\endgroup
+****************** Fin code ******************
+
+
+****************** Code 367 ******************
+\edef\foo{\scantokens{Bonjour le monde}}% produit une erreur
+****************** Fin code ******************
+
+
+****************** Code 368 ******************
+\expandafter\def\expandafter\foo\expandafter
+	{\scantokens{Bonjour le monde}}% produit une erreur
+****************** Fin code ******************
+
+
+****************** Code 369 ******************
+
+Voici la macro \string\foo\ : \foo.
+****************** Fin code ******************
+
+
+****************** Code 370 ******************
+\catcode`\@11
+\def\scandef#1#2{% #1=\<macro>   #2=<texte>
+	\begingroup
+		\endlinechar=-1 % pas de caract\xE8re de fin de ligne
+		\everyeof{\@nil#1\noexpand}% ajoute "\@nil\<macro>\noexpand" avant la fin du fichier
+		\expandafter\scandef at i\expandafter\relax\scantokens{#2}%
+}
+\def\scandef at i#1\@nil#2{% "\@nil#2" ont \xE9t\xE9 ajout\xE9 par \everyeof
+	\endgroup% ferme le groupe
+	\expandafter\def\expandafter#2\expandafter{\gobone#1}% et d\xE9finit la \<macro>
+}
+\catcode`@12
+\def\foo{%
+	Dans tout l'argument de \string\foo, <<~>> est actif
+	sauf
+	\catcode`\~12
+	\scandef\bar{dans celui de \string\bar : <<~>>}%
+	\catcode`~13
+	\bar
+}
+\foo
+****************** Fin code ******************
+
+
+****************** Code 371 ******************
+{%
+\endlinechar=`\d% ins\xE8re la lettre "d" \xE0 chaque fin de ligne
+% le \noexpan(d) est incomplet
+Voici la macro \string\foo\ : \foo.% fins de ligne...
+}% ...comment\xE9es pour \xE9viter le "d"
+****************** Fin code ******************
+
+
+****************** Code 372 ******************
+\catcode`\@11
+\def\cprotect#1{% #1 est la \<macro>
+	\def\cprotect at i##1{% ##1 est l'<argument>
+		\endgroup% ferme le groupe pr\xE9c\xE9demment ouvert
+		#1{\scantokens{##1\noexpand}}%
+	}%
+	\begingroup% rend tous les octets de catcode12
+		\for\cprotect at temp=0to255\do{\catcode\cprotect at temp=12 }%
+		\catcode`\{=1 \catcode`\}=2 % sauf "{" et "}"
+		\cprotect at i% puis, lit l'argument
+}
+\catcode`@12
+\frboxsep=1.5pt 
+1) \cprotect\frbox{foo \litterate-&#  #^   ^_%- bar}\par
+2) \cprotect\frbox{\catcode`\~=12 a~b~c~d}\par
+3) \cprotect\frbox{foo \litterate-\bar- \cprotect\frbox{\litterate-&#   #-} fin}
+****************** Fin code ******************
+
+
+****************** Code 373 ******************
+\catcode`@11
+\def\Cprotect#1{% #1 est la \<macro>
+	\def\Cprotect at i##1{% ##1 est la liste des arguments
+		\endgroup% ferme le groupe pr\xE9c\xE9demment ouvert
+		\toks0={#1}% met la \<macro> dans le registre de tokens
+		\Cprotect at ii##1\quark% \quark est mis \xE0 la fin des arguments
+		\the\toks0 % ex\xE9cute le registre
+	}%
+	\begingroup% rend tous les octets de catcode12
+		\for\temp at arg= 0 to 255 \do{% changer \xE0 12 tous les catcodes
+			\unless\ifnum\catcode\temp at arg=1 % sauf si catcode=1
+				\unless\ifnum\catcode\temp at arg=2 % ou 2
+					\catcode\temp at arg=12
+				\fi
+			\fi}%
+		\Cprotect at i% puis, lit l'argument
+}
+\def\Cprotect at ii#1{% #1 est l'argument courant (d\xE9pouill\xE9 de ses accolades)
+	\def\temp at arg{#1}% stocke l'argument pour le tester ci dessous :
+	\unless\ifx\quark\temp at arg% si la fin n'est pas atteinte
+		% ajouter "{\scantokens{#1\noexpand}}" au registre
+		\addtotoks{\toks0}{{\scantokens{#1\noexpand}}}%
+		\expandafter\Cprotect at ii% et recommencer
+	\fi
+}
+\catcode`@12
+
+\def\test#1#2{Bonjour #1 et #2}
+\Cprotect\test{{argument 1 : \litterate-\foo-}{argument 2 : \litterate-\bar-}}
+****************** Fin code ******************
+
+
+****************** Code 374 ******************
+\newdimen\pixelsize \newdimen\pixelsep
+\def\pixel{\vrule height\pixelsize width\pixelsize depth0pt }
+\def\vblankpixel{\vrule height\pixelsize width0pt depth0pt }
+\def\blankpixel{\vblankpixel \vrule height0pt width\pixelsize depth0pt }
+\def\gap{\kern\pixelsep}
+\pixelsize=3pt \pixelsep=1pt 
+Essai :
+\vbox{% aligne verticalement
+	\offinterlineskip% annule le ressort d'interligne
+	\lineskip=\pixelsep\relax% pour le mettre \xE0 \pixelsep
+	\hbox{\pixel\gap\blankpixel\gap\blankpixel\gap\blankpixel\gap\pixel}% 1re ligne
+	\hbox{\pixel\gap\pixel     \gap\blankpixel\gap\pixel     \gap\pixel}% 2e ligne
+}
+****************** Fin code ******************
+
+
+****************** Code 375 ******************
+\pixelsize=3pt \pixelsep=1pt 
+Essai :
+\vtop{%
+  \offinterlineskip \lineskip=\pixelsep\relax
+  \vbox{%
+    \hbox{\blankpixel\gap\pixel     \gap\pixel     \gap\pixel}%         ***
+    \hbox{\pixel     \gap\blankpixel\gap\blankpixel\gap\pixel}%        *  *
+    \hbox{\pixel     \gap\blankpixel\gap\blankpixel\gap\pixel}%        *  *
+    \hbox{\pixel     \gap\blankpixel\gap\blankpixel\gap\pixel}%        *  *
+    \hbox{\blankpixel\gap\pixel     \gap\pixel     \gap\pixel}%         ***
+  }%                                                      ----ligne de base
+  \hbox  {\blankpixel\gap\blankpixel\gap\blankpixel\gap\pixel}%           *
+  \hbox  {\blankpixel\gap\pixel     \gap\pixel               }%         **
+}
+****************** Fin code ******************
+
+
+****************** Code 376 ******************
+\catcode`\@11
+\begingroup% dans ce groupe :
+\catcode`\ =12\relax% l'espace devient un "caract\xE8re autre"
+\catcode`\^^M=13\relax% le retour \xE0 la ligne est actif
+\edef^^M{\string,}% et se d\xE9veloppe en une virgule (de catcode 12)
+\global\deftok\otherspc{ }% d\xE9finit un espace de catcode 12
+\xdef\letter at code{% macro contenant le dessin de la lettre "e"
+ **
+*  *
+***
+*
+ ***}%
+\endgroup
+
+\def\makecar at i#1{% #1 = dessin de la lettre avec les caract\xE8res "," "*" et " "
+	\doforeach\current at line\in{#1}% pour chaque ligne dans #1 :
+		{\ifx\empty\current at line% si la ligne est vide
+			\addtomacro\pixabove{\hbox{\vblankpixel}}% ajouter une fausse ligne
+		\else% sinon
+			\let\pix at line\empty% initialiser le code de la ligne \xE0 vide
+			\expandafter\makecar at ii\current at line\quark% et la construire
+		\fi
+		}%
+}
+
+\def\makecar at ii#1{% #1=caract\xE8re de dessin de la ligne en cours
+	\ifxcase#1% si le caract\xE8re est
+		*        {\addtomacro\pix at line\pixel}%
+		\otherspc{\addtomacro\pix at line\blankpixel}%
+	\endif
+	\ifx#1\quark% si la fin est atteinte 
+		\addtomacro\pix at line\unkern% annuler le dernier espace interpixel
+		\eaddtomacro\pixabove{% et encapsuler \pix at line dans une \hbox
+		\expandafter\hbox\expandafter{\pix at line}}%
+	\else% si la fin n'est pas atteinte, ajouter l'espace interpixel
+		\addtomacro\pix at line\gap
+		\expandafter\makecar at ii% recommencer avec le caract\xE8re suivant
+	\fi
+}
+\pixelsize=3pt \pixelsep=1pt 
+\let\pixabove\empty% initialisation de la macro finale \xE0 vide
+\exparg\makecar at i\letter at code% appelle la macro qui construit \pixabove
+La lettre
+\vtop{% enferme le tout dans une \vtop :
+	\offinterlineskip\lineskip=\pixelsep% ajuste l'espace interligne
+	\vbox{\pixabove}% affiche le caract\xE8re cr\xE9\xE9
+}.
+****************** Fin code ******************
+
+
+****************** Code 377 ******************
+\catcode`\@11
+\begingroup% dans ce groupe :
+\catcode`\ =12\relax% l'espace devient un "caract\xE8re autre"
+\catcode`\^^M=13\relax% le retour \xE0 la ligne est actif
+\edef^^M{\string,}% et se d\xE9veloppe en une virgule (de catcode 12)
+\global\deftok\otherspc{ }% d\xE9finit un espace de catcode 12
+\xdef\letter at code{% macro contenant le dessin de la lettre "g"
+ ***
+*  *
+*  *
+*  *
+ ***_
+   *
+ **}%
+\endgroup
+
+\def\makecar#1#2{% #1=nom recevant le code final  #2=macro contenant le dessin
+	\let\pixabove\empty \let\pixbelow\empty \let\pix at line\empty% initialise \xE0 vide
+	\exparg\ifin{#2}_% si le code contient _
+		{\expandafter\makecar at iii#2\@nil}% aller \xE0 \makecar at iii
+		{\exparg\makecar at i{#2}}% sinon, \xE0 \makecar at i
+	\edef#1{% d\xE9finit la macro #1 comme
+		\vtop{% une \vtop contenant :
+			\unexpanded{\offinterlineskip\lineskip\pixelsep}% r\xE9glage d'espace inter ligne
+			\vbox{\unexpanded\expandafter{\pixabove}}% \vbox des pixels au-dessus
+			                                         % de la ligne de base
+			\unless\ifx\pixbelow\empty% s'il y a des pixels au-dessous de la baseline
+				\unexpanded\expandafter{\pixbelow}% les ajouter dans la \vtop
+			\fi
+			}%
+		}%
+}
+
+\def\makecar at iii#1_,#2\@nil{%
+	\makecar at i{#2}% construit la partie au-dessous de la baseline
+	\let\pixbelow\pixabove% et affecte le code \xE0 \pixbelow
+	\let\pixabove\empty \let\pix at line\empty% r\xE9-initialise
+	\makecar at i{#1}% construit la partie au-dessus de la baseline
+}
+
+\makecar\lettreg\letter at code
+\catcode`\@12
+\pixelsize=3pt \pixelsep=1pt 
+
+Essai : \lettreg
+****************** Fin code ******************
+
+
+****************** Code 378 ******************
+\catcode`\@11
+\begingroup
+\expandafter\gdef\csname impact@" "\endcsname{% d\xE9finit la lettre "espace"
+	\hskip 4\pixelsize plus.5\pixelsize minus.5\pixelsize\relax}%
+\catcode`\^^M=13\relax% le retour \xE0 la ligne est actif
+\edef^^M{\string,}% et se d\xE9veloppe en une virgule (de catcode 12)
+\catcode`\ =12\relax% l'espace devient un "caract\xE8re autre"
+\gdef\impact at alphabet{
+a/
+***
+   *
+ ***
+*  *
+****,
+b/
+*
+*
+***
+*  *
+*  *
+*  *
+***,
+% beaucoup de caract\xE8res omis
+9/
+ ***
+*   *
+*   *
+ ****
+    *
+    *
+ ***,
+0/
+ ***
+*   *
+*   *
+* * *
+*   *
+*   *
+ ***,
+error/
+* * *
+ * *
+* * *
+ * *
+* * *
+ * *
+* * *}% <- commenter la fin de ligne
+\endgroup%
+% On parcourt le texte de remplacement de \impact at alphabet
+\edef\saved at crcatcode{\catcode13=\the\catcode13\relax}%
+\catcode`\^^M=13\relax% le retour \xE0 la ligne est actif
+\edef^^M{\string,}% et se d\xE9veloppe en une virgule (de catcode 12)
+\expsecond{\doforeach\letter at name/\letter at code\in}\impact at alphabet%
+	{\edef\letter at name{\letter at name}% d\xE9veloppe la lettre (^^M devient ",")
+	\edef\letter at code{\letter at code}% d\xE9veloppe le code (^^M devient ",")
+	\exparg\ifstart\letter at name,% si la lettre commence par ","
+		{\edef\letter at name{\expandafter\gobone\letter at name}}% la retirer
+		{}%
+	\exparg\ifstart\letter at code,% si le code commence par ","
+		{\edef\letter at code{\expandafter\gobone\letter at code}}% la retirer
+		{}%
+	\expandafter\makecar\csname impact@"\letter at name"\endcsname\letter at code%
+	}%
+\saved at crcatcode% redonne le catcode de ^^M
+% % d\xE9finit l'espace
+\pixelsize=3pt \pixelsep=1pt 
+% puis, on affiche ce qui a \xE9t\xE9 d\xE9fini :
+a = \csname impact@"a"\endcsname\qquad b = \csname impact@"b"\endcsname\qquad
+9 = \csname impact@"9"\endcsname \qquad 0 = \csname impact@"0"\endcsname\qquad
+error = \csname impact@"error"\endcsname
+****************** Fin code ******************
+
+
+****************** Code 379 ******************
+\catcode`\@11
+\newskip\letter at skip% ressort mis entre chaque lettre
+\def\impactend{\impactend}% d\xE9finit le quark de fin
+
+\newmacro\impact[0.2ex][0pt]{% d\xE9finit la macro \xE0 arguments optionnels
+	\leavevmode% passer en mode horizontal
+	\begingroup% dans un groupe semi-simple :
+		\pixelsize=#1\relax \pixelsep=#2\relax% d\xE9finir ces deux dimensions
+		\letter at skip=#1 plus.1\pixelsize minus.1\pixelsize\relax% d\xE9finir espace inter-lettre
+		\baselineskip=% d\xE9finir la distance entre les lignes de base
+			\dimexpr12\pixelsize+7\pixelsep\relax% \xE0 12\pixelsize+7\pixelsep
+		\lineskiplimit=0pt % si lignes trop serr\xE9es
+		\lineskip=2\pixelsize\relax% les espacer de 2\pixelsize
+		\impact at i% puis aller voir le prochain token
+}
+
+% va voir le prochain token puis va le tester \xE0 \impact at ii
+\def\impact at i{\futurelet\nxtletter\impact at ii}
+
+\def\impact at ii{%
+		\ifx\nxtletter\impactend% si le token est \let \xE9gal \xE0 \impactend
+			\let\donext\impact at endprocess% aller \xE0 al macro de fin
+		\else
+			\ifx\nxtletter\sptoken% si c'est un espace
+				\let\donext\impact at spc% aller \xE0 \impact at spc
+			\else
+				\let\donext\impact at arg% sinon, aller \xE0 \impact at arg
+			\fi
+		\fi
+		\donext% faire l'action d\xE9cid\xE9e ci-dessus
+}
+
+% mange un espace (argument d\xE9limit\xE9) et affiche "\letter@<spc>"
+\expandafter\def\expandafter\impact at spc\space{%
+		\csname impact@" "\endcsname
+		\impact at i% puis va voir le prochain token
+}
+%
+% lit l'argument suivant
+\def\impact at arg#1{%
+		\csname impact@% affiche
+			\ifcsname impact@"#1"\endcsname
+				"#1"% le caract\xE8re \impact@"#1" s'il est d\xE9fini
+			\else
+				"error"% sinon \impact@"error"
+			\fi
+		\endcsname
+		\hskip\letter at skip% ins\xE9rer le ressort inter-lettre
+		\impact at i% puis, aller voir le prochain token
+}
+\def\impact at endprocess\impactend{% macro ex\xE9cut\xE9 lorsqque le quark \impactend va \xEAtre lu
+		\unskip% annuler le dernier ressort
+		\par% composer le paragraphe pour prendre en compte
+		    % \baselineskip, \lineskip et \lineskiplimit
+	\endgroup% et fermer le groupe
+}
+\catcode`\!=12 % rend le point d'exclamation "gentil"
+\impact Programmer en {TEX} est facile et tr{e`}s utile !\impactend\par
+\impact[2pt][0.5pt]Programmer en {TEX} est facile et tr{e`}s utile !\impactend
+****************** Fin code ******************
+
+
+****************** Code 380 ******************
+\newdimen\maingraddim \maingraddim=4pt % hauteur des graduations principales
+\newdimen\maingradwd \maingradwd=0.5pt % \xE9paisseur des graduations principales
+\def\maingradx#1{%
+	\lower1.5ex\clap{$\scriptscriptstyle#1$}% afficher l'argument au dessous
+	\clap{\vrule height\maingraddim width\maingradwd depth0pt }% et la r\xE9glure
+}
+D\xE9but\maingradx{1}suite\maingradx{2}conclusion\maingradx{3}fin.
+****************** Fin code ******************
+
+
+****************** Code 381 ******************
+\maingraddim=4pt \maingradwd=0.5pt
+\newdimen\axiswd \axiswd=0.5pt 
+\newmacro\xaxis[1cm]1[1]1[4]{%% #1= dist  #2=xmin  #3=inc  #4=xmax  #5=subdiv
+	\hbox{% mettre le tout dans une \hbox
+		\rlap{% en d\xE9bordement \xE0 droite :
+			\FOR\xx = #2 to #4 \do #3{% pour chaque graduation principale
+				\maingradx{\xx}% tracer la graduation et \xE9crire l'abscisse
+				\kern#1\relax% puis se d\xE9placer vers la droite
+			}%
+		}%
+		\vrule% tracer l'axe des abscisses
+			height\axiswd% d'epaisseur \axiswd, de longueur #1*(#4-#2)/#3
+			width\dimexpr#1*\decdiv{\dimtodec\dimexpr#4pt-#2pt\relax}{#3}\relax
+			depth 0pt\relax % et de profondeur nulle
+	}%
+}
+a) \xaxis{-2}{5}suite
+
+b) \frboxsep=0pt\frbox{\xaxis[1.25cm]{-1}[0.25]{1}}suite
+****************** Fin code ******************
+
+
+****************** Code 382 ******************
+\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt
+\newdimen\subgraddim \subgraddim=2.5pt 
+\newdimen\subgradwd \subgradwd=0.2pt
+% trace un trait de subdivision
+\def\subgradx{\clap{\vrule height\subgraddim width\subgradwd depth0pt }}
+
+\newmacro\xaxis[1cm]1[1]1[4]{% #1= dist  #2=xmin  #3=inc  #4=xmax  #5=subdiv
+	\hbox{% tout mettre dans une \hbox
+		\setbox0=\hbox{% stocke dans une \hbox les grad secondaires entre 2 unit\xE9s
+			\edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions
+			\for\xx=1 to #5-1 \do{% ins\xE9rer #5-1 fois
+				\kern\dimsubgrad% une espace secondaire
+				\subgradx% une graduation secondaire
+				}%
+		}%
+		\rlap{% en d\xE9bordement \xE0 droite :
+			\FOR\xx = #2 to #4 \do #3{% pour chaque graduation principale
+				\maingradx{\xx}% imprimer l'abscisse
+				\ifdim\xx pt<#4pt % et en d\xE9bordement \xE0 droite,
+					\rlap{\copy0 }% les r\xE9glures secondaires, sauf pour la derni\xE8re
+				\fi
+				\kern#1\relax% se d\xE9placer vers la droite
+			}%
+		}%
+		\vrule% tracer l'axe des abscisses
+			height\axiswd% d'epaisseur \axiswd, de longueur #1*(#4-#2)/#3
+			width\dimexpr#1*\decdiv{\dimtodec\dimexpr#4pt-#2pt\relax}{#3}\relax
+			depth 0pt\relax % et de profondeur nulle
+	}%
+}
+a) \xaxis{-2}{5}[2]
+
+)b \xaxis[1.25cm]{-1}[0.25]{1}[5]
+****************** Fin code ******************
+
+
+****************** Code 383 ******************
+\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt
+\subgraddim=2.5pt \subgradwd=0.2pt
+\def\maingrady#1{% affiche...
+	\vlap{\llap{$\scriptscriptstyle#1$\kern2pt }}% l'ordonn\xE9e...
+	\vbox to0pt{\vss\hrule height\maingradwd width\maingraddim depth0pt }% et la r\xE9glure
+}
+
+% affiche une subdiv
+\def\subgrady{\vlap{\hrule height\subgradwd width\subgraddim depth0pt }}
+\newmacro\yaxis[1cm]1[1]1[4]{%
+% #1= dist  #2=ymin  #3=inc  #4=ymax  #5=subdiv
+	\vbox{%
+		\offinterlineskip% d\xE9sactiver le ressort d'interligne
+		\setbox0=\vbox{% stocke dans une \hbox les grad secondaires entre 2 unit\xE9s
+			\edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions
+			\for\xx=1 to #5-1 \do{% ins\xE9rer #5-1 fois
+				\kern\dimsubgrad% une espace secondaire
+				\subgrady% une graduation secondaire
+				}%
+		}%
+		\edef\dimsubgrad{\the\dimexpr#1/#5\relax}% distance entre 2 subdivisions
+		\vbox to 0pt{% en d\xE9bordement vers le bas
+			\FOR\xx = #4to#2\do-#3{%
+				\maingrady{\xx}% imprimer l'abscisse
+				\ifdim\xx pt>#2pt % et en d\xE9bordement \xE0 droite,
+					\vbox to 0pt{\copy0 \vss}% les r\xE9glures secondaires, sauf pour la derni\xE8re
+				\fi
+				\kern#1\relax% se d\xE9placer vers la droite
+			}%
+			\vss% assure le d\xE9bordement vers le bas
+		}%
+		\clap{\vrule% tracer l'axe des ordonn\xE9es
+			width\axiswd% d'\xE9paisseur \axiwd, et de hauteur (#4-#2)/#3*#1
+			height\decdiv{\dimtodec\dimexpr(#4pt-#2pt)\relax}{#3}\dimexpr#1\relax
+			depth 0pt\relax % profondeur nulle
+		}%
+	}%
+}
+
+Essai : \yaxis{-2}{5}[2]\qquad \frboxsep=0pt \frbox{\yaxis[0.75cm]{-1}[0.5]{3}[5]}
+****************** Fin code ******************
+
+
+****************** Code 384 ******************
+\newdimen\xunit \xunit=1cm 
+\newdimen\yunit \yunit=0.75cm
+\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt
+\subgraddim=2.5pt \subgradwd=0.2pt
+\catcode`@11
+\newmacro\graphzone1[1]1[4]1[1]1[4]{%
+	\leavevmode% quitter le mode vertical
+	\begingroup% travailler dans un groupe semi-simple
+		\def\graphxmin{#1}\def\graphxmax{#3}% sauvegarder
+		\def\graphymin{#5}\def\graphymax{#7}% les
+		\def\xincrement{#2}\def\yincrement{#6}% arguments
+		\setbox0\hbox{\yaxis[\yunit]{#5}[#6]{#7}[#8]}% axe "y" dans boite 0
+		\setbox1\hbox{\xaxis[\xunit]{#1}[#2]{#3}[#4]}% axe "x" dans boite 1
+		\edef\graphboxht{\the\ht0 }% \graphboxh est la hauteur de la zone
+		\edef\graphboxwd{\the\wd1 }% \graphboxw est la largeur de la zone
+		\rlap{% annuler la dimension horizontale, et...
+			\box1 % ...afficher l'axe (Ox) puis
+			% le trait vertical \xE0 l'extr\xEAme droite de la zone
+			\clap{\vrule height\dimexpr\graphboxht+\axiswd\relax width\axiswd depth0pt }%
+			}%
+		\rlap{\box0 }% afficher l'axe (Oy) en annulant sa dimension horizontale
+		\raise\graphboxht% puis monter tout en haut de la zone
+			% pour tracer le trait horizontal en annulant sa longueur
+			\rlap{\kern-0.5\axiswd% et en rattrapant le centrage de l'axe des ordonn\xE9es
+				\vrule height\axiswd width\dimexpr\graphboxwd+\axiswd}%
+		\begingroup% pour lire l'argument "<code>" :
+			\catcode`\^^M=9\relax % ignorer les retours \xE0 la ligne
+			\graphzone at i% appeler \graphzone at i
+}
+\def\graphzone at i#1{% lire le <code>...
+		\endgroup% et fermer le groupe pr\xE9c\xE9demment ouvert
+		\setbox0\hbox{#1}% mettre les instructions graphique dans la boite 0
+		\wd0=\dimexpr\graphboxwd+\axiswd\relax% forcer sa dim horizontale
+		\ht0=\dimexpr\graphboxht+\axiswd\relax% et verticale
+		% pour correspondre aux dimension de la zone graphique
+		\box0 % l'afficher
+	\endgroup% sortir du groupe initial
+}
+\catcode`@12
+essai\graphzone{-1}[0.5]{1.5}[5]{-20}[10]{10}[2]{\relax}fin
+****************** Fin code ******************
+
+
+****************** Code 385 ******************
+\def\putat#1#2#3{%
+	\leavevmode\rlap{\kern#1\vbox to0pt{\vss\hbox{#3}\kern#2}}%
+}
+Essai\putat{0.5cm}{0.3cm}{A}\putat{-0.2cm}{-0.1cm}{B}\putat{0pt}{0.2cm}{C}suite
+****************** Fin code ******************
+
+
+****************** Code 386 ******************
+\def\ifinside#1[#2,#3]{%
+	\ifnum\sgn{\dimexpr#1pt-#2pt\relax}\sgn{\dimexpr#1pt-#3pt}1=1 
+		\expandafter\secondoftwo
+	\else
+		\expandafter\firstoftwo
+	\fi
+}
+1) \ifinside3.5[0.5,4]{vrai}{faux}\qquad
+2) \ifinside-0.2[-0.4,-0.3]{vrai}{faux}\qquad
+3) \ifinside-0.999[-1,-0.5]{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 387 ******************
+\def\fonction#1{\dimtodec\dimexpr
+	\decmul{#1}{\decmul{#1}{#1}}pt% x^3
+	-\decmul{#1}{#1}pt% -x^2
+	-#1pt*3% -3x
+	+2pt\relax}% +2
+1) \fonction{-4}\qquad% doit afficher -66
+2) \fonction{-1.7}\qquad %  doit afficher -0.703
+3) \fonction{1}\qquad%  doit afficher -1
+4) \fonction{1.35}%  doit afficher -1.412125
+****************** Fin code ******************
+
+
+****************** Code 388 ******************
+\newmacro\cross[2pt][0.2pt]{%
+	% #1=dimensions de traits depuis le centre de la croix
+	% #2=\xE9paisseur des traits
+	\leavevmode
+	\vlap{%
+		\clap{%
+			\vrule height#2 depth0pt width#1 % 1/2 trait horizontal gauche
+			\vrule height#1 depth#1 width#2  % trait vertical
+			\vrule height#2 depth0pt width#1 % 1/2 trait horizontal droit
+		}%
+	}%
+}
+Une croix : \cross{}puis une autre\cross[8pt][0.8pt]
+****************** Fin code ******************
+
+
+****************** Code 389 ******************
+\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt
+\subgraddim=2.5pt \subgradwd=0.2pt
+\xunit=1.25cm \yunit=0.75cm
+
+\def\maingradx#1{%
+	\lower1.5ex\clap{$\scriptscriptstyle#1$}% afficher l'argument au dessous
+	\clap{\vrule height\maingraddim width\maingradwd depth0pt }% et la r\xE9glure
+}
+
+\def\subgradx{\clap{\vrule height\subgraddim width\subgradwd depth0pt }}
+
+\newmacro\xaxis[1cm]1[1]1[4]{%
+	\hbox{% tout mettre dans une \hbox
+		\setbox0=\hbox{% stocke dans une \hbox les grad secondaires entre 2 unit\xE9s
+			\edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions
+			\for\xx=1 to #5-1 \do{% ins\xE9rer #5-1 fois
+				\kern\dimsubgrad% une espace secondaire
+				\subgradx% une graduation secondaire
+				}%
+		}%
+		\rlap{% en d\xE9bordement \xE0 droite :
+			\FOR\xx = #2 to #4 \do #3{% pour chaque graduation principale
+				\maingradx{\xx}% imprimer l'abscisse
+				\ifdim\xx pt<#4pt % et en d\xE9bordement \xE0 droite,
+					\rlap{\copy0 }% les r\xE9glures secondaires, sauf pour la derni\xE8re
+				\fi
+				\kern#1\relax% se d\xE9placer vers la droite
+			}%
+		}%
+		\vrule% tracer l'axe des abscisses
+			height\axiswd% d'epaisseur \axiswd, de longueur #1*(#4-#2)/#3
+			width\dimexpr#1*\decdiv{\dimtodec\dimexpr#4pt-#2pt\relax}{#3}\relax
+			depth 0pt\relax % et de profondeur nulle
+	}%
+}
+
+\def\maingrady#1{% affiche...
+	\vlap{\llap{$\scriptscriptstyle#1$\kern2pt }}% l'ordonn\xE9e...
+	\vbox to0pt{\vss\hrule height\maingradwd width\maingraddim depth0pt }% et la r\xE9glure
+}
+
+% affiche une subdiv
+\def\subgrady{\vlap{\hrule height\subgradwd width\subgraddim depth0pt }}
+% #1= dim entre 2 grad principales #2=abscisse d\xE9part #3=incr\xE9ment
+% #4=abscisse arriv\xE9e #5=nb intervalles secondaires
+\newmacro\yaxis[1cm]1[1]1[4]{%
+	\vbox{%
+		\offinterlineskip% d\xE9sactiver le ressort d'interligne
+		\setbox0=\vbox{% stocke dans une \hbox les grad secondaires entre 2 unit\xE9s
+			\edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions
+			\for\xx=1 to #5-1 \do{% ins\xE9rer #5-1 fois
+				\kern\dimsubgrad% une espace secondaire
+				\subgrady% une graduation secondaire
+				}%
+		}%
+		\edef\dimsubgrad{\the\dimexpr#1/#5\relax}% distance entre 2 subdivisions
+		\vbox to 0pt{% en d\xE9bordement vers le bas
+			\FOR\xx = #4to#2\do-#3{%
+				\maingrady{\xx}% imprimer l'abscisse
+				\ifdim\xx pt>#2pt % et en d\xE9bordement \xE0 droite,
+					\vbox to 0pt{\copy0 \vss}% les r\xE9glures secondaires, sauf pour la derni\xE8re
+				\fi
+				\kern#1\relax% se d\xE9placer vers la droite
+			}%
+			\vss% assure le d\xE9bordement vers le bas
+		}%
+		\clap{\vrule% tracer l'axe des ordonn\xE9es
+			width\axiswd% d'\xE9paisseur \axiwd, et de hauteur (#4-#2)/#3*#1
+			height\decdiv{\dimtodec\dimexpr(#4pt-#2pt)\relax}{#3}\dimexpr#1\relax
+			depth 0pt\relax % profondeur nulle
+		}%
+	}%
+}
+
+\catcode`@11
+\newmacro\graphzone1[1]1[4]1[1]1[4]{%
+	\leavevmode% quitter le mode vertical
+	\begingroup% travailler dans un groupe semi-simple
+		\def\graphxmin{#1}\def\graphxmax{#3}% sauvegarder
+		\def\graphymin{#5}\def\graphymax{#7}% les
+		\def\xincrement{#2}\def\yincrement{#6}% arguments
+		\setbox0\hbox{\yaxis[\yunit]{#5}[#6]{#7}[#8]}% axe "y" dans boite 0
+		\setbox1\hbox{\xaxis[\xunit]{#1}[#2]{#3}[#4]}% axe "x" dans boite 1
+		\edef\graphboxht{\the\ht0 }% \graphboxh est la hauteur de la zone
+		\edef\graphboxwd{\the\wd1 }% \graphboxw est la largeur de la zone
+		\rlap{% annuler la dimension horizontale, et...
+			\box1 % ...afficher l'axe (Ox) puis
+			% le trait vertical \xE0 l'extr\xEAme droite de la zone
+			\clap{\vrule height\dimexpr\graphboxht+\axiswd\relax width\axiswd depth0pt }%
+			}%
+		\rlap{\box0 }% afficher l'axe (Oy) en annulant sa dimension horizontale
+		\raise\graphboxht% puis monter tout en haut de la zone
+			% pour tracer le trait horizontal en annulant sa longueur
+			\rlap{\kern-0.5\axiswd% et en rattrapant le centrage de l'axe des ordonn\xE9es
+				\vrule height\axiswd width\dimexpr\graphboxwd+\axiswd}%
+		\begingroup% pour lire l'argument "<code>" :
+			\catcode`\^^M=9\relax % ignorer les retours \xE0 la ligne
+			\graphzone at i% appeler \graphzone at i
+}
+\def\graphzone at i#1{% lire le <code>...
+		\endgroup% et fermer le groupe pr\xE9c\xE9demment ouvert
+		\xunit=\decdiv1\xincrement\xunit% divise les unit\xE9s par l'incr\xE9ment
+		\yunit=\decdiv1\yincrement\yunit
+		\setbox0\hbox{#1}% mettre les instructions graphique dans la boite 0
+		\wd0=\dimexpr\graphboxwd+\axiswd\relax% forcer sa dim horizontale
+		\ht0=\dimexpr\graphboxht+\axiswd\relax% et verticale
+		% pour correspondre aux dimension de la zone graphique
+		\box0 % l'afficher
+	\endgroup% sortir du groupe initial
+}
+
+\def\putat#1#2#3{%
+	\leavevmode\rlap{\kern#1\vbox to0pt{\vss\hbox{#3}\kern#2}}%
+}
+
+\newmacro\cross[2pt][0.2pt]{%
+	\leavevmode
+	\vlap{%
+		\clap{%
+			\vrule height#2 depth0pt width#1 % 1/2 terait horizontal gauche
+			\vrule height#1 depth#1 width#2  % trait vertical
+			\vrule height#2 depth0pt width#1 % 1/2 trait horizontal droit
+		}%
+	}%
+}
+
+\def\plot(#1,#2){% place "\plotstuff" aux coordonn\xE9es #1,#2
+	\edef\x at plot{#1}\edef\y at plot{#2}% d\xE9velopper au cas o\xF9
+	\ifinside\x at plot[\graphxmin,\graphxmax]% si #1 est dans les limites
+		{\ifinside\y at plot[\graphymin,\graphymax]% et si #2 l'est aussi
+			{\putat% placer aux coordonn\xE9es
+				{\dimexpr\x at plot\xunit-\graphxmin\xunit\relax}% X=(x-xmin)/xinc
+				{\dimexpr\y at plot\yunit-\graphymin\yunit\relax}% Y=(y-ymin)/yinc
+				\plotstuff% le contenu de \plotstuff
+			}%
+			\relax
+		}
+		\relax
+}
+
+\def\showxaxis{% affiche l'axe (Ox)
+	\ifinside0[\graphymin,\graphymax]%
+		{\putat\z@{-\graphymin\yunit}{\vlap{\vrule width\graphboxwd height\axiswd}}}%
+		\relax
+}
+
+\def\showyaxis{% affiche l'axe (Oy)
+	\ifinside0[\graphxmin,\graphxmax]%
+		{\putat{-\graphxmin\xunit}\z@{\clap{\vrule width\axiswd height\graphboxht}}}%
+		\relax
+}
+
+\def\showaxis{\showxaxis\showyaxis}% affiche les deux axes
+\catcode`@12
+
+%%%%%%%%%%%%%%% 1er exemple :
+\xunit=1cm \yunit=0.5cm
+\def\fonction#1{\dimtodec\dimexpr\decmul{#1}{\decmul{#1}{#1}}pt-%
+	\decmul{#1}{#1}pt-#1pt*3+2pt\relax}
+Exemple 1 :\qquad
+\graphzone{-2}[0.5]{2.5}[5]{-5}{5}[2]{%
+	\let\plotstuff\cross% d\xE9finit ce qu'il faut afficher comme point
+	\FOR\xx=-2 to 2.5 \do 0.1{%
+		\plot(\xx,\fonction{\xx})% afficher les points de coordonn\xE9es (x ; f(x))
+	}%
+	\putat{5pt}{\dimexpr\graphboxht-10pt\relax}% afficher
+		{$f(x)=x^3-x^2-3x+2$}% la fonction trac\xE9e
+	\showaxis% et les axes
+}\par\medskip
+%%%%%%%%%%%%% 2e exemple
+\xunit=0.7cm \yunit=\xunit
+\def\foncx#1{\dimtodec\dimexpr\decmul{#1}{\decmul{#1}{#1}}pt-%
+	\decmul{4}{\decmul{#1}{#1}}pt-#1pt+4pt}
+\def\foncy#1{\dimtodec\dimexpr\decmul{#1}{#1}pt-#1pt*2-6pt}
+Exemple 2 :\qquad
+\graphzone{-12}[2]{12}[2]{-8}[2]{8}[2]{%
+	\def\plotstuff{\cross[1.25pt]}
+	\FOR\tt = -5 to 5 \do 0.1 {%
+		\plot(\foncx\tt,\foncy\tt)%
+	}%
+	\putat{5pt}{\dimexpr\graphboxht-20pt\relax}% afficher la fonction param\xE9trique trac\xE9e
+		{$\left\{\vcenter{\hbox{$x(t)=t^3-4t^2-t-4$}\hbox{$y(t)=t^2-2t-6$}}\right.$}%
+	\showaxis
+}
+****************** Fin code ******************
+
+
+****************** Code 390 ******************
+\def\mandeltest#1#2{%
+	\def\zx{0}\def\zy{0}% zn=0 + i*0
+	\def\zxx{0}\def\zyy{0}% carr\xE9s de \zx et \zy
+	\def\mandelresult{1}% le point appartient \xE0 M a priori
+	\for\ii=1to\maxiter\do1{%
+		\advance\count255 by1
+		\edef\zy{\dimtodec\dimexpr\decmul{\decmul2\zx}\zy pt+#2pt\relax}%
+		\edef\zx{\dimtodec\dimexpr\zxx pt-\zyy pt+#1pt\relax}%%
+		\edef\zxx{\decmul\zx\zx}%
+		\edef\zyy{\decmul\zy\zy}%
+		\ifdim\dimexpr\zxx pt+\zyy pt\relax>4pt
+			\def\mandelresult{0}%
+ 			\exitfor\ii
+		\fi
+	}%
+}
+\def\mandel#1#2{% #1=points par unit\xE9 #2=nombre maximal d'it\xE9rations
+	\graphzone{-2}[1]{1}[2]{-1}[1]{1}[2]{%
+		\def\maxiter{#2}%
+		\edef\plotstuff{\the\dimexpr\xunit/#1\relax}% taille d'un pixel
+		\edef\plotstuff{\vrule height\plotstuff width\plotstuff}%
+		\edef\increment{\decdiv{1}{#1}}% incr\xE9ment
+		\count255=0 % compteur des it\xE9rations
+		\FOR\xxx = -2 to 1 \do \increment{% pour chaque
+			\FOR\yyy = 0 to 1 \do \increment{% pixel du domaine
+				\mandeltest\xxx\yyy% tester s'il est dans M
+				\ifnum\mandelresult=1 % si oui,
+					\plot(\xxx,\yyy)\plot(\xxx,-\yyy)% afficher les 2 points
+				\fi
+			}%
+		}%
+	\edef\plotstuff{$\scriptstyle\number\count255 $}% affiche la valeur du compteur
+	\plot(-1.99,0.92)% aux coordonn\xE9es (-1.99 ; 0.92)
+	}%
+}
+\xunit=3cm \yunit=3cm \mandel{400}{500}
+****************** Fin code ******************
+
+
+****************** Code 391 ******************
+\catcode`\@11
+\protected\def\numsep{\kern0.2em }% \numsep est le s\xE9parateur mis tous les 3 chiffres
+
+\def\formatdecpart#1{% #1=s\xE9rie de chiffres
+	\ifempty{#1}% si la partie d\xE9cimale est vide
+		{}% ne rien afficher
+		{{,}\formatdecpart at i 1.#1..}% sinon, afficher la virgule et mettre en forme
+}
+
+% #1=compteur de caract\xE8res #2= chiffre courant
+% #3= chiffres restants     #4 = chiffres d\xE9j\xE0 trait\xE9s
+\def\formatdecpart at i#1.#2#3.#4.{%
+	\ifempty{#3}% si #2 est le dernier chiffre
+		{#4#2}% le mettre en derni\xE8re position et tout afficher, sinon
+		{\ifnum#1=3 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			% si 3 chiffres sont atteint, rendre #1 \xE9gal \xE0 1 et
+			{\formatdecpart at i 1.#3.#4#2\numsep.}% mettre #2\numsep en dernier puis recommencer
+			% sinon, mettre #2 en derni\xE8re position et recommencer
+			% tout en incr\xE9mentant #1 de 1
+			{\expandafter\formatdecpart at i \number\numexpr#1+1.#3.#4#2.}%
+		}%
+}
+a) \formatdecpart{1234567}\qquad
+b) \formatdecpart{987125}\qquad
+c) \formatdecpart{56}\qquad
+d) \edef\foo{\formatdecpart{2014}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 392 ******************
+\catcode`\@11
+\protected\def\numsep{\kern0.2em }% \numsep est le s\xE9parateur mis tous les 3 chiffres
+\def\formatintpart#1{% #1=s\xE9rie de chiffres
+	\formatintpart at i 1.#1..% appelle la macro r\xE9cursive
+}
+
+% #1=compteur de caract\xE8res #2= chiffre courant
+% #3= chiffres restants     #4 = chiffres d\xE9j\xE0 trait\xE9s
+\def\formatintpart at i#1.#2#3.#4.{%
+	\ifempty{#3}% si #2 est le dernier chiffre
+		{#2#4}% le mettre en premi\xE8re position et tout afficher, sinon
+		{\ifnum#1=3 \expandafter\firstoftwo\else\expandafter\secondoftwo
+		\fi% si 3 chiffres sont atteint, rendre #1 \xE9gal \xE0 1 et
+			{\formatintpart at i 1.#3.\numsep#2#4.}% mettre "\numsep#2" en premier et recommencer
+			% sinon, mettre #2 en premi\xE8re position et recommencer
+			% tout en incr\xE9mentant #1 de 1
+			{\expandafter\formatintpart at i \number\numexpr#1+1.#3.#2#4.}%
+		}%
+}
+\catcode`\@12
+a) \formatintpart{1234567}\qquad b) \formatintpart{987125}\qquad
+c) \formatintpart{56}\qquad
+d) \edef\foo{\formatintpart{2014}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 393 ******************
+\catcode`\@11
+\def\formatintpart#1{% #1=s\xE9rie de chiffres
+	\expandafter\formatintpart at i\expandafter1\expandafter.\romannumeral\reverse{#1\z@}..%
+}
+
+\catcode`\@12
+a) \formatintpart{1234567}\qquad b) \formatintpart{987125}\qquad
+c) \formatintpart{56}\qquad
+d) \edef\foo{\formatintpart{2014}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 394 ******************
+\catcode`\@11
+\def\ifnodecpart#1{\if at nodecpart#1.\@nil}% teste si #1 est un entier
+\def\if at nodecpart#1.#2\@nil{\ifempty{#2}}
+
+\def\formatnum#1{%
+	\ifnodecpart{#1}% s'il n'y a pas de partie d\xE9cimale
+		{\formatintpart{#1}}% formatter la partie enti\xE8re
+		{\formatnum at i#1\@nil}% sinon, formatter les deux parties
+}
+
+\def\formatnum at i#1.#2\@nil{%
+	\formatintpart{#1}% formatte la partie enti\xE8re
+	\formatdecpart{#2}% et la partie d\xE9cimale
+}
+
+\catcode`\@12
+a) \formatnum{3.1415926}\qquad
+b) \formatnum{1987654.12301}\qquad
+c) \edef\foo{\formatnum{0987654.12300}}$\foo$
+****************** Fin code ******************
+
+
+****************** Code 395 ******************
+\catcode`\@11
+\def\removefirstzeros#1{%
+	\removefirstzeros at i#1\quark% ajoute "\quark" en dernier
+}
+\def\removefirstzeros at i#1{% #1=chiffre courant
+	\ifx\quark#1% fin atteinte donc nombre = 0
+		\expandafter0% laisser un z\xE9ro
+	\else
+		\ifx0#1% si le chiffre lu est un 0
+			\expandafter\expandafter\expandafter\removefirstzeros at i% recommencer
+		\else% sinon remettre le chiffre #1 et tout afficher jusqu'\xE0 \removefirstzeros at i
+			\expandafter\expandafter\expandafter\removefirstzeros at ii
+			\expandafter\expandafter\expandafter#1%
+		\fi
+	\fi
+}
+\def\removefirstzeros at ii#1\quark{#1}
+\catcode`\@12
+a) \removefirstzeros{000325478}\qquad
+b) \removefirstzeros{00000}\qquad
+c) \edef\foo{\removefirstzeros{001000}}\meaning\foo\qquad
+d) \long\def\>#1<{\detokenize{#1}}
+   \expandafter\>\romannumeral\removefirstzeros{0123}<
+****************** Fin code ******************
+
+
+****************** Code 396 ******************
+\long\def\>#1<{\detokenize{#1}}
+\expandafter\>\romannumeral-`\@\removefirstzeros{000123}<
+****************** Fin code ******************
+
+
+****************** Code 397 ******************
+\catcode`\@11
+\def\removelastzeros#1{%
+	\exparg\reverse% inverser apr\xE8s
+		{\romannumeral-`\.% tout d\xE9velopper
+			\expandafter\removelastzeros at i% enlever les 0 de gauche apr\xE8s
+			\romannumeral\reverse{#1\z@}\quark% avoir invers\xE9 #1
+		}%
+}
+\def\removelastzeros at i#1{% enl\xE8ve tous les 0 de gauche
+	\unless\ifx\quark#1% si la fin n'est pas atteinte
+		\ifx0#1% si le chiffre lu est un 0
+			\expandafter\expandafter\expandafter\removelastzeros at i% recommencer
+		\else% sinon remettre le chiffre et tout afficher jusqu'\xE0 \removefirstzeros at i
+			\expandafter\expandafter\expandafter\removelastzeros at ii
+			\expandafter\expandafter\expandafter#1%
+		\fi
+	\fi
+}
+\def\removelastzeros at ii#1\quark{#1}
+\catcode`\@12
+a) \removelastzeros{0003254780}\qquad
+b) \removelastzeros{00000}\qquad
+c) \edef\foo{\removelastzeros{001000}}\foo\qquad
+\long\def\>#1<{\detokenize{#1}}
+d) \expandafter\>\romannumeral-`\.\removelastzeros{012300}<
+****************** Fin code ******************
+
+
+****************** Code 398 ******************
+\catcode`\@11
+\protected\def\numsep{\kern0.2em }% \numsep est le s\xE9parateur mis tous les 3 chiffres
+
+\def\formatdecpart#1{% #1=s\xE9rie de chiffres
+	\ifempty{#1}% si la partie d\xE9cimale est vide
+		{}% ne rien afficher
+		{{,}\formatdecpart at i 1.#1..}% sinon, afficher la virgule et mettre en forme
+}
+
+% #1=compteur de caract\xE8res #2= chiffre courant
+% #3= chiffres restants     #4 = chiffres d\xE9j\xE0 trait\xE9s
+\def\formatdecpart at i#1.#2#3.#4.{%
+	\ifempty{#3}% si #2 est le dernier chiffre
+		{#4#2}% le mettre en derni\xE8re position et tout afficher, sinon
+		{\ifnum#1=3 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			% si 3 chiffres sont atteint, rendre #1 \xE9gal \xE0 1 et
+			{\formatdecpart at i 1.#3.#4#2\numsep.}% mettre #2\numsep en dernier puis recommencer
+			% sinon, mettre #2 en derni\xE8re position et recommencer
+			% tout en incr\xE9mentant #1 de 1
+			{\expandafter\formatdecpart at i \number\numexpr#1+1.#3.#4#2.}%
+		}%
+}
+
+\def\formatintpart#1{% #1=s\xE9rie de chiffres
+	\expandafter\formatintpart at i\expandafter1\expandafter.%
+	\romannumeral\reverse{#1\z@}..% appelle la macro r\xE9cursive
+}
+
+% #1=compteur de caract\xE8res #2= chiffre \xE0 d\xE9placer
+% #3= chiffres restants     #4 = chiffres d\xE9j\xE0 trait\xE9s
+\def\formatintpart at i#1.#2#3.#4.{%
+	\ifempty{#3}% si #2 est le dernier chiffre \xE0 traiter
+		{#2#4}% le mettre en premi\xE8re position et tout afficher, sinon
+		{\ifnum#1=3 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			% si 3 chiffres sont atteint, rendre #1 \xE9gal \xE0 1 et
+			{\formatintpart at i 1.#3.\numsep#2#4.}% mettre \numsep#2 en premier puis recommencer
+			% sinon, mettre #2 en derni\xE8re position et recommencer
+			% tout en incr\xE9mentant #1 de 1
+			{\expandafter\formatintpart at i\number\numexpr#1+1.#3.#2#4.}%
+		}%
+}
+\def\removefirstzeros#1{%
+	\removefirstzeros at i#1\quark% ajoute "\quark" en dernier
+}
+\def\removefirstzeros at i#1{% #1=chiffre courant
+	\ifx\quark#1% fin atteinte donc nombre = 0
+		\expandafter0% laisser un z\xE9ro
+	\else
+		\ifx0#1% si le chiffre lu est un 0
+			\expandafter\expandafter\expandafter\removefirstzeros at i% recommencer
+		\else% sinon remettre le chiffre #1 et tout afficher jusqu'\xE0 \removefirstzeros at i
+			\expandafter\expandafter\expandafter\removefirstzeros at ii
+			\expandafter\expandafter\expandafter#1%
+		\fi
+	\fi
+}
+\def\removefirstzeros at ii#1\quark{#1}
+
+\def\removelastzeros#1{%
+	\exparg\reverse% inverser apr\xE8s
+		{\romannumeral-`\.% tout d\xE9velopper
+			\expandafter\removelastzeros at i% enlever les 0 de gauche apr\xE8s
+			\romannumeral\reverse{#1\z@}\quark% avoir invers\xE9 #1
+		}%
+}
+\def\removelastzeros at i#1{% enl\xE8ve tous les 0 de gauche
+	\unless\ifx\quark#1% si la fin n'est pas atteinte
+		\ifx0#1% si le chiffre lu est un 0
+			\expandafter\expandafter\expandafter\removelastzeros at i% recommencer
+		\else% sinon remettre le chiffre et tout afficher jusqu'\xE0 \removefirstzeros at i
+			\expandafter\expandafter\expandafter\removelastzeros at ii
+			\expandafter\expandafter\expandafter#1%
+		\fi
+	\fi
+}
+\def\removelastzeros at ii#1\quark{#1}
+
+% renvoie vrai s'il n'y a pas de partie d\xE9cimale
+\def\if at nodecpart#1.#2\@nil{\ifempty{#2}}
+
+\def\formatnum#1{\formatnum at i1!#1!}
+
+% #1 = <s\xE9rie de signes> suivie de "1"
+% #2 = caract\xE8re courant
+% #3 = caract\xE8res non trait\xE9s
+\def\formatnum at i#1!#2#3!{%
+	\ifx+#2\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{\ifempty{#3}% si #2=+ et #3 est vide
+			{\number#1 }% afficher "+1" ou "-1" (il n'y avait que des signes)
+			{\formatnum at i#2#1!#3!}% sinon, mettre le signe #2 devant #1
+		}
+		{\ifx-#2\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			{\ifempty{#3}% si #2=- et #3 est vide
+				{\number#1 }% afficher "+1" ou "-1" (il n'y avait que des signes)
+				{\formatnum at i#2#1!#3!}% sinon, mettre le signe #2 devant #1
+			}% #2 est le dernier caract\xE8re qui n'est pas un signe + ou -
+			{\ifnum#1<0 -\fi% si "<signes>1" est <0 afficher un "-"
+			\formatnum at ii{#2#3}% formatter le nombre form\xE9 avec "#2#3""
+			}%
+		}%
+}
+
+\def\formatnum at ii#1{%
+	\if at comma{#1}% si #1 comporte une virgule
+		{\formatnum at iii#1\@nil}% la remplacer par un "." et recommencer
+		{\if at nodecpart#1.\@nil% puis si les chiffres restants sont un entier
+			{\formatintpart{#1}}% formatter l'entier
+			{\formatnum at iv#1\@nil}% sinon, formatter le nombre
+		}%
+}
+
+\def\formatnum at iii#1,#2\@nil{\formatnum at ii{#1.#2}}
+
+\def\formatnum at iv#1.#2\@nil{% formatte le nombre d\xE9cimal #1.#2
+	\exparg\formatintpart{\romannumeral-`\.\removefirstzeros{#1}}%
+	\exparg\formatdecpart{\romannumeral-`\.\removelastzeros{#2}}%
+}
+
+\def\if at comma#1{\if at comma@i#1,\@nil}% teste la pr\xE9sence d'un virgule dans #1
+\def\if at comma@i#1,#2\@nil{\ifempty{#2}\secondoftwo\firstoftwo}
+\catcode`\@12
+
+a) \formatnum{3,141592653589793238462643383279502884197169399375105820974944592}\par
+b) \formatnum{---+69874}\qquad
+c) \formatnum{0032100,98000}\qquad
+d) \formatnum{+++010.01100}\qquad
+e) \formatnum{-+--+}\qquad
+f) \formatnum{---00.0000}\qquad
+g) \formatnum{+99,0000}\qquad
+h) \formatnum{.123456}\par
+i) \edef\foo{\formatnum{-+-+-010500,090900}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 399 ******************
+\setbox0=\vbox{%
+	\hbox{Premi\xE8re ligne}
+	\hbox{Deuxi\xE8me ligne}
+	\hbox{Avant-derni\xE8re ligne}
+	\hbox{Derni\xE8re ligne}
+}
+
+\frboxsep=0pt % aucun espace entre le contenu et l'encadrement
+Boite initiale de hauteur \the\ht0 {} : \frbox{\copy0 }
+\splittopskip0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1=\vsplit0 to 22pt % couper la boite \xE0 22pt de hauteur
+
+Boite 1 de hauteur \the\ht1 {} : \frbox{\box1 }
+
+Boite 0 de hauteur \the\ht0 {} : \frbox{\box0 }
+****************** Fin code ******************
+
+
+****************** Code 400 ******************
+\setbox0=\vbox{%
+	\hbox{Premi\xE8re ligne}
+	\hbox{Deuxi\xE8me ligne}
+	\hbox{Avant-derni\xE8re ligne}
+	\hbox{Derni\xE8re ligne}
+}
+
+\edef\restorevbadness{\vbadness=\the\vbadness\relax}% restaurera le \vbadness
+\vbadness=10000 % plus d'avertissement pour boite verticale
+\frboxsep=0pt % aucun espace entre le contenu et l'encadrement
+Boite initiale de hauteur \the\ht0 {} : \frbox{\copy0 }
+\splittopskip0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1=\vsplit0 to 22pt % couper la boite \xE0 22pt de hauteur
+\setbox1=\vbox{\unvbox1 }% la boite 1 prend la hauteur naturelle
+\restorevbadness\relax% restaure le \vbadness
+
+Boite 1 de hauteur \the\ht1 {} : \frbox{\box1 }
+
+Boite 0 de hauteur \the\ht0 {} : \frbox{\box0 }
+****************** Fin code ******************
+
+
+****************** Code 401 ******************
+\catcode`@11
+\newbox\remainbox
+\newbox\partialbox
+\newdimen\cut at ht
+
+\def\breakpar{%
+	\par\nointerlineskip% termine le paragraphe pr\xE9c\xE9dent
+	\vskip\frboxsep\relax% et saute une petite espace verticale
+	\begingroup
+		\splittopskip\topskip% \topskip en haut des boites coup\xE9es
+		\topskip=0pt % neutraliser le \topskip
+		% nbre de r\xE9glures horizontales contribuant \xE0 l'encadrement restant (2 au d\xE9but)
+		\def\coeff at rule{2}%
+		\setbox\remainbox=\vbox\bgroup% compose la boite apr\xE8s avoir...
+			\advance\hsize by -2\dimexpr\frboxrule+\frboxsep\relax% ajust\xE9 sa largeur
+}
+
+\def\endbreakpar{%
+		\egroup% fin de la composition de la boite
+		\def\rule at arg{ULR}% prendre l\cut at htes r\xE9glures d'encadrement haute, gauche et droite
+		\splitbox% puis, aller \xE0 l'algorithme de coupure
+	\endgroup% une fois fini, sortir du groupe semi-simple
+}
+
+\def\splitbox{%
+	\ifvoid\remainbox% si la boite est vide, c'est la fin du processus
+		\par\nointerlineskip% termine le paragraphe pr\xE9c\xE9dent
+		\vskip\frboxsep\relax% et saute un petit espace vertical
+	\else% sinon
+		\expandafter\splitbox at i% aller \xE0 \splitbox at i
+	\fi
+}
+
+\def\splitbox at i{%
+	\hbox{}% composer un noeud en mode vertical
+	\nointerlineskip% pas de ressort d'interligne
+	% calculer la dimension verticale disponible dans la page pour le texte de la boite
+	\cut at ht=\dimexpr\pagegoal-\pagetotal-(\frboxsep+\frboxrule)*\coeff at rule\relax
+	% si dimension totale du texte > dimension disponible pour le texte
+	\ifdim\dimexpr\ht\remainbox+\dp\remainbox>\cut at ht% si une coupure doit \xEAtre faite
+			\advance\cut at ht\dimexpr%   augmenter Dv de l'espace verticale lib\xE9r\xE9e
+				+\frboxsep+\frboxrule% par la r\xE9glure inf\xE9rieure qui n'est pas sur cette page
+				\relax
+		\edef\old at vbadness{\the\vbadness}% sauvegarder \badness
+		\vbadness=10000 % d\xE9sactive les avertissement lors de la coupure
+		\def\coeff at rule{1}% ne prendre en compte que r\xE9glure D + espace D
+		\setbox\partialbox=\vsplit\remainbox to\cut at ht% coupe \xE0 la hauteur calcul\xE9e
+		% \partialbox retrouve sa hauteur naturelle
+		\setbox\partialbox=\vbox{\unvbox\partialbox}%
+		\vbadness=\old at vbadness\relax% restaure \vbadness
+		\printpartialbox% imprime la boite partielle
+		\vfill\eject% et compose la page en cours
+	\else% si une coupure n'est pas n\xE9cessaire :
+		\setbox\remainbox\vbox{\unvbox\remainbox}% reprendre la hauteur naturelle
+		\setbox\partialbox=\box\remainbox% \partialbox devient \remainbox
+		                                 % et cette derni\xE8re devient vide
+		\cut at ht=\dimexpr\ht\partialbox+\dp\partialbox\relax% hauteur \xE0 encadrer
+		\edef\rule at arg{\rule at arg D}% ajouter "D" aux r\xE9glures \xE0 tracer
+		\printpartialbox% afficher la boite restante
+	\fi
+	\splitbox
+}
+
+\def\printpartialbox{% imprime \partialbox
+	\expandafter\framebox\expandafter[\rule at arg]{%
+		\vbox to\cut at ht{\unvbox\partialbox\vss}}%
+	\def\rule at arg{LR}% ne mettre que les r\xE9glures d et g
+}
+
+\def\dummytext#1{%
+	\for\xx=1to#1\do% composer #1 fois la phrase suivante :
+		{Ceci est un texte sans aucun int\'er\^et dont le seul but est de meubler
+		la page artificiellement.
+		}%
+}
+
+\catcode`@12
+\dummytext{5}
+\frboxsep=5pt 
+
+\breakpar
+	\dummytext{70}
+\endbreakpar
+
+\dummytext{5}
+****************** Fin code ******************
+
+
+****************** Code 402 ******************
+\setbox0=\vbox{%
+	\hsize=5cm 
+	Ceci est un texte sans aucun int\xE9r\xEAt dont le seul but est de meubler
+	la page de fa\xE7on artificielle.
+}
+
+Boite 0 : \copy0 % affiche la boite totale
+\medbreak
+
+\edef\restorevfuzz{\vfuzz=\the\vfuzz\relax}% appel\xE9e apr\xE8s la coupure
+\vfuzz=\maxdimen% annule les avertissements pour d\xE9bordement
+\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1=\vsplit0 to 0pt % couper la boite \xE0 0pt de hauteur
+\restorevfuzz% restaurer \vfuzz
+\setbox1=\vbox{\unvbox1}% redonner \xE0 la boite sa hauteur d'origine
+
+Boites 1+0 : \vbox{%
+	\offinterlineskip% annule le ressort d'interligne
+	\box1 % affiche la premi\xE8re ligne
+	\box0 %affiche les lignes restantes
+}
+****************** Fin code ******************
+
+
+****************** Code 403 ******************
+\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}% hauteur totale de la boite #1
+\setbox0=\vbox{%
+	\hsize=5cm Ceci est un texte sans aucun int\xE9r\xEAt dont le seul but est
+	de meubler la page de fa\xE7on artificielle.
+}
+\edef\htbefore{\the\vdim0}% hauteur de la boite 0
+
+Boite 0 : \copy0 % affiche la boite totale
+\medbreak
+
+\edef\restoreparam{%
+	\vfuzz=\the\vfuzz\relax% sauvegarde le \vfuzz
+	\splittopskip=\the\splittopskip% et \splittopskip
+}%
+\vfuzz=\maxdimen% annule les avertissements pour d\xE9bordement
+\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1=\vsplit0 to 0pt % couper la boite \xE0 0pt de hauteur
+\restoreparam
+\setbox1=\vbox{\unvbox1}% redonner \xE0 la boite sa hauteur d'origine
+
+\edef\intersplitspace{\the\dimexpr\htbefore-(\vdim0+\vdim1)\relax}%
+Boites 1+0 : \vbox{%
+	\offinterlineskip% annule le ressort d'interligne
+	\box1 % affiche la premi\xE8re ligne
+	\vskip\intersplitspace\relax% ajoute le ressort perdu \xE0 la coupure
+	\box0 % affiche les lignes restantes
+}
+****************** Fin code ******************
+
+
+****************** Code 404 ******************
+\setbox0=\vbox{%
+	\hsize=5cm Ceci est un texte sans aucun int\xE9r\xEAt dont le seul but est
+	de meubler la page de fa\xE7on artificielle.
+}
+
+Boite 0 : \copy0 % affiche la boite totale
+\medbreak
+
+\edef\restoreparam{%
+	\vfuzz=\the\vfuzz\relax% sauvegarde le \vfuzz
+	\splittopskip=\the\splittopskip\relax% , le \splittopskip
+	\savingvdiscards=\the\savingvdiscards\relax% et le \savingvdiscards
+	}%
+\vfuzz=\maxdimen% annule les avertissements pour d\xE9bordement
+\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante
+\savingvdiscards=1 % autorise la sauvagarde des \xE9l\xE9ments supprim\xE9s
+\setbox1=\vsplit0 to 0pt % couper la boite \xE0 0pt de hauteur
+\setbox1=\vbox{\unvbox1}% redonner \xE0 la boite sa hauteur d'origine
+\restoreparam
+
+Boites 1+0 : \vbox{%
+	\offinterlineskip% annule le ressort d'interligne
+	\box1 % affiche la premi\xE8re ligne
+	\splitdiscards% affiche les \xE9l\xE9ments ignor\xE9s
+	\box0 % affiche les lignes restantes
+}
+****************** Fin code ******************
+
+
+****************** Code 405 ******************
+\catcode`@11
+\newbox\remainbox% boite contenant le texte total
+\newbox\currentline% boite contenant le ligne en cours
+\newcount\linecnt% compteur pour num\xE9roter les lignes
+
+\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}% hauteur totale de la boite #1
+
+\newmacro\leftline[0pt]{% d\xE9finit ce qui se trouve \xE0 gauche de chaque ligne
+	\def\wd at left{#1}%
+	\def\stuff at left
+}
+
+\newmacro\rightline[0pt]{% d\xE9finit ce qui se trouve \xE0 droite de chaque ligne
+	\def\wd at right{#1}%
+	\def\stuff at right
+}
+
+\let\formatline=\identity% par d\xE9faut, afficher chaque ligne telle quelle
+
+% Par d\xE9faut :
+\leftline[11pt]{$\scriptscriptstyle\number\linecnt$\kern3pt }% num\xE9rotation \xE0 gauche
+\rightline{}% rien \xE0 droite
+
+\def\numlines{%
+	\par\smallskip
+	\begingroup% dans un groupe semi-simple
+		\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante
+		\linecnt=0 % initialiser le compteur de lignes
+		\savingvdiscards=1 % autorise la sauvagarde des \xE9l\xE9ments supprim\xE9s
+		\setbox\remainbox=\vbox\bgroup% compose la boite...
+			\advance\hsize by% diminuer la \hsize
+			-\dimexpr\wd at left+\wd at right\relax% de la largeur des contenus
+}
+
+\def\endnumlines{%
+	\egroup
+	\offinterlineskip
+	\split at line
+}
+
+\def\split at line{%
+	\ifvoid\remainbox% si la boite est vide
+		\par% fin du processus
+		\endgroup% fermer le groupe ouvert au d\xE9but
+	\else% sinon
+		\advance\linecnt 1 % incr\xE9mente le compteur de lignes
+		\edef\htbefore{\the\vdim\remainbox}%
+		\edef\restorevfuzz{\vfuzz=\the\vfuzz\relax}% sauvegarde le \vfuzz
+		\vfuzz=\maxdimen% annule les avertissements pour d\xE9bordement
+		\setbox\currentline=\vsplit\remainbox to 0pt % couper la boite \xE0 0pt de hauteur
+		\restorevfuzz
+		\setbox\currentline=\vbox{\unvbox\currentline}% redonner \xE0 la boite sa hauteur
+		\edef\intersplitspace{% calcul de l'espace vertical perdu \xE0 la coupure
+			\the\dimexpr\htbefore-(\vdim\remainbox+\vdim\currentline)\relax
+		}%
+		\hbox{% en mode vertical et dans une hbox, afficher :
+			\hbox to\wd at left{\hss\stuff at left}%   1) ce qui est \xE0 gauche
+			\formatline{\box\currentline}%       2) la ligne courante
+			\hbox to\wd at right{\stuff at right\hss}% 3) ce qui est \xE0 droite
+		}%
+		\splitdiscards% affiche ce qui a \xE9t\xE9 ignor\xE9 \xE0 la coupure
+		\expandafter\split at line% recommencer
+	\fi
+}
+
+\def\dummytext#1{%
+	\for\xx=1to#1\do% composer #1 fois la phrase suivante :
+		{Ceci est un texte sans aucun int\xE9r\xEAt dont le seul but est de meubler
+		la page de fa\xE7on artificielle. }%
+}
+
+\catcode`@12
+\parindent=2em 
+
+ESSAI 1 :
+\numlines
+	\dummytext{2}\par% 2 phrases
+	$$1+1=2$$\par% des maths
+	\dummytext{1}\par% une phrase
+	\hrulefill\par% un leaders
+	\dummytext{2}% 2 phrases
+	\hrule height2pt depth 2pt %une \hrule
+	\vskip10pt % saute 10pt verticalement
+	\dummytext{1}% une phrase
+\endnumlines\medbreak
+
+ESSAI 2 :
+\leftline{}\rightline{}% rien \xE0 gauche et rien \xE0 droite
+\frboxsep=-\frboxrule% encadrer vers "l'int\xE9rieur"
+\let\formatline\frbox% lignes encadr\xE9es
+\numlines
+	\dummytext{4}
+\endnumlines\medbreak
+
+ESSAI 3 :
+\let\formatline\identity
+\leftline[7pt]{%
+	\for\xx= 1 to 2 \do{% ins\xE9rer 2 fois
+		\setbox0=\hbox{% % mettre dans une \hbox une \vrule de "bonnes dimensions"
+			\vrule height\ht\currentline depth\dimexpr\dp\currentline+\intersplitspace
+			       width0.5pt }%
+		\dp0=\dp\currentline% r\xE9ajuster la profondeur (c-\xE0-d enlever \intersplitspace)
+		\box0 % afficher le boite
+		\kern2pt % et ins\xE9rer un espace horizontal de 2pt apr\xE8s chaque r\xE9glure verticale
+		}%
+	\kern2pt % ajouter 2pt de plus entre les lignes et le texte
+}
+
+\rightline[10pt]{\kern5pt $\scriptscriptstyle\number\linecnt$}% num\xE9roter \xE0 droite
+
+\numlines
+	\dummytext{2}
+
+	$$a^2+b^2=c^2$$
+
+	\dummytext{2}
+\endnumlines
+****************** Fin code ******************
+
+
+****************** Code 406 ******************
+% d\xE9finition des ressorts "inter-lettre" et "inter-mot"
+\newskip\interletterskip \interletterskip=0.25em plus0.05em minus0.05em 
+\newskip\interwordskip   \interwordskip=3\interletterskip\catcode`\@11 
+\catcode`@11
+\def\spreadtxt at testtoken#1{% macro qui teste le token
+	\ifcat\noexpand#1\sptoken% si le token est un espace
+		\parseadd{%
+			\unskip% retirer le pr\xE9c\xE9dent ressort
+			\hskip\interwordskip}% et ajouter le ressort inter-mot
+	\else
+		\ifcat\noexpand#1a% si le token est une lettre
+			\parseadd{#1\hskip\interletterskip}% ajouter le ressort inter-lettre
+		\else
+			\ifcat\noexpand#1.% si le token est "autre", comme le "."
+				\parseadd{#1\hskip\interletterskip}% ajouter le ressort inter-lettre
+			\else% sinon
+				\parseadd{#1}% ajouter le token lu
+			\fi
+		\fi
+	\fi
+	\parse at i
+}
+\def\spreadtxt{%
+	\ifstarred% si \xE9toil\xE9e
+		{\spreadtxt at i{\parse*}}% appeler \parse*
+		{\spreadtxt at i{\parse}}% sinon, appeler \parse
+}
+\def\spreadtxt at i#1#2{% #1= appel "\parse*" ou "\parse"   #2 = texte \xE0 espacer
+	\begingroup% dans un groupe
+		\let\testtoken=\spreadtxt at testtoken% modifier \testtoken
+		#1#2\parsestop% et appeler \parse
+	\endgroup
+}
+\catcode`@12
+
+\spreadtxt{Comme on le voit sur cet exemple, une espace est ins\xE9r\xE9e apr\xE8s
+{\it chaque} caract\xE8re de catcode 10, 11 ou 12.}
+\medbreak
+
+\spreadtxt*{Comme on le voit sur cet exemple, une espace est ins\xE9r\xE9e apr\xE8s
+{\it chaque} caract\xE8re de catcode 10, 11 ou 12.}
+****************** Fin code ******************
+
+
+****************** Code 407 ******************
+\newskip\interletterskip
+\newskip\interwordskip 
+\catcode`\@11
+\newtoks\spacetxt at toks%  le registre qui contient le texte final
+
+\def\spacetxt{%
+	\let\spacetxt at endprocess\spacetxt at endnormal
+	% d\xE9finit la macro appel\xE9e en fin de processus -> a priori : fin normale
+	\ifstarred% si la macro est \xE9toil\xE9e
+		{\let\spacetxt at recurse\spacetxt at star% d\xE9finir la macro r\xE9cursive
+		\spacetxt at i% et aller \xE0 \spacetxt at i
+		}% sinon
+		{\let\spacetxt at recurse\spacetxt at nostar% d\xE9finir la macro r\xE9cursive
+		\spacetxt at i% et aller \xE0 \spacetxt at i
+		}%
+}
+
+\newmacro\spacetxt at i[0.3em plus0.07em minus.07em][3\interletterskip]1{%
+% arg optionnel #1 et #2 = ressorts inter-lettre et inter--mot
+% #3 = texte \xE0 espacer
+	\interletterskip=#1\relax
+	\interwordskip=#2\relax
+	\def\spacetxt at code{#3}% met le texte \xE0 espacer dans \spacetxt at code
+	\spacetxt at toks{}% initialiser le registre contenant le texte final
+	\spacetxt at recurse% aller \xE0 la macro r\xE9cursive pr\xE9c\xE9demment d\xE9finie
+}
+
+\newif\if at indivifound% bool\xE9en qui sera vrai si un motif sp\xE9cial est rencontr\xE9
+
+\def\rightofsc#1#2{%
+	\exparg\ifin{#1}{#2}% si #1 contient le #2
+		{\def\right at of##1#2##2\@nil{\def#1{##2}}%
+		\expandafter\right at of#1\@nil% appelle la macro auxiliaire
+		}%
+		{\let#1=\empty}% sinon, #1 est vide
+}
+
+\def\spacetxt at nostar{%
+	\exparg\ifempty{\spacetxt at code}% si texte restant est vide
+		\spacetxt at endprocess% aller \xE0 la fin du processus
+		{\@indivifoundfalse% sinon, a priori, les motifs non r\xE9guliers ne sont pas trouv\xE9s
+		% pour chaque \indivi at tmp dans \indivilist
+		\expsecond{\doforeach\indivi at tmp\in}{\indivilist}% pour chaque motif indivisible
+			{% si le code commence par le motif courant
+			\exptwoargs\ifstartwith\spacetxt at code\indivi at tmp
+				{% l'ajouter dans le registre ainsi que l'espace inter-lettre
+				\eaddtotoks\spacetxt at toks{\indivi at tmp\hskip\interletterskip}%
+				% et enlever le motif du texte restant \xE0 lire
+				\expsecond{\rightofsc\spacetxt at code}{\indivi at tmp}%
+				\@indivifoundtrue% marquer qu'un motif a \xE9t\xE9 trouv\xE9
+				\doforeachexit% et sortir pr\xE9matur\xE9ment de la boucle
+				}%
+				\relax% si le code ne commence pas le motif courant -> ne rien faire
+			}%
+		\unless\if at indivifound% si aucun motif n'a \xE9t\xE9 trouv\xE9			
+			\grab at first\spacetxt at code\spacetxt at temp% retirer le 1er caract\xE8re du texte
+			\ifx\spacetxt at temp\space% si le 1er caract\xE8re est un espace
+				\addtotoks\spacetxt at toks{%
+					\unskip% annuler le pr\xE9c\xE9dent ressort
+					\hskip\interwordskip}% ajouter l'espace inter-mot au registre de token
+			\else% si le 1er caract\xE8re n'est pas un espace
+				% ajouter ce caract\xE8re et l'espace inter-lettre au registre de token
+				\eaddtotoks\spacetxt at toks{\spacetxt at temp\hskip\interletterskip}%
+			\fi
+		\fi
+		\spacetxt at recurse% enfin, continuer le processus
+		}%
+}
+
+\def\spacetxt at star{%
+	\exparg\ifempty{\spacetxt at code}% si texte restant est vide
+		\spacetxt at endprocess% aller \xE0 la fin du processus
+		{% sinon, si texte commence par "{"
+		\exparg\ifbracefirst{\spacetxt at code}%
+			{\grab at first\spacetxt at code\spacetxt at temp
+			% mettre {<argument} dans \spacetxt at temp
+			\begingroup% ouvrir un groupe
+			% mettre le contenu de l'argument dans \spacetxt at code
+			\expandafter\def\expandafter\spacetxt at code\spacetxt at temp
+			\let\spacetxt at endprocess\spacetxt at endingroup% changer le processus de fin
+			\spacetxt at toks{}% initialiser
+			\spacetxt at recurse% ex\xE9cuter le processus avec ce nouveau texte
+			}% si le code ne commence pas par "{", aller \xE0 \spacetxt at nostar mais comme
+			\spacetxt at nostar% \spacetxt at recurse vaut \spacetxt at star, n'y faire qu'1 boucle
+		}%
+}
+
+\def\spacetxt at endnormal{% fin de processus normal
+	\the\spacetxt at toks% afficher le registre \xE0 token
+	\unskip% et supprimer le dernier ressort
+}
+
+\def\spacetxt at endingroup{% fin du processus dans un groupe :
+	\expandafter\endgroup\expandafter% avant de fermer le groupe
+	\addtotoks\expandafter\spacetxt at toks\expandafter% ajouter au registre hors du groupe
+		{\expandafter{\the\spacetxt at toks}}% ce qui est collect\xE9 localement mis entre {}
+	\spacetxt at recurse% puis aller \xE0 la macro r\xE9cursive
+}
+
+\catcode`\@12
+\def\indivilist{\xE9,\xE8}% liste des motifs sp\xE9ciaux
+\spacetxt*{Comme on le voit sur cet exemple, une espace est ins\xE9r\xE9e apr\xE8s
+{\it chaque} caract\xE8re.}
+\medbreak
+
+\def\indivilist{\xE9,es,au,<<,>>}
+\spacetxt[4pt plus.7pt minus.7pt][12pt plus2pt minus2pt]{Ici, les motifs <<es>> et <<au>>
+restent indivisibles et la ligature des guillemets devient possible en d\xE9clarant "<<" et
+">>" comme motifs.}
+****************** Fin code ******************
+
+
+****************** Code 408 ******************
+\catcode`\@11
+\def\ttcode#1{% lit #1, le <d\xE9limiteur> de d\xE9but
+	\def\ttcode at i##1#1{% ##1 = <texte> entre d\xE9limiteurs
+		\tt% passe en fonte \xE0 chasse fixe
+		\setbox0=\hbox{ }%
+		\edef\spc at wd{\the\wd0 }% longueur d'un espace
+		\spacetxt
+			[.1pt plus0pt minus.1pt]% espace inter-lettre
+			[\glueexpr\wd0+.3pt plus.1pt minus.1pt\relax]% espace inter-mot
+			{##1}% le <texte> est compos\xE9 par \spacetxt
+		\endgroup
+	}%
+	\begingroup
+		\def\indivilist{<<,>>,{,,},--}% (rajouter \xE0, \xE9, \xE8, etc. en codage UTF8)
+		\def\do##1{\catcode`##1=12 }%
+		\dospecials% rend inoffensifs tous les tokens sp\xE9ciaux
+		\letactive\ =\space % rend l'espace actif
+		\ttcode at i% va lire le <texte> et le d\xE9limiteur de fin
+}
+\catcode`\@12
+
+\hfill\vrule\vbox{%
+	\hsize=.75\hsize
+	Avec \ttcode/\ttcode/, on peut ins\xE9rer une adresse internet <<
+	\ttcode-http://www.gutenberg.eu.org/Typographie- >> puis repasser en fonte normale
+	puis \ttcode+m\xEAme composer un court passage en fonte \xE0 chasse fixe -- m\xEAme si les
+	coupures de mots se font n'importe o\xF9 -- et aussi afficher tous les caract\xE8res
+	sp\xE9ciaux <<{$^ _$#}&+>>, et finir en fonte normale\ldots
+}\vrule\hfill\null
+****************** Fin code ******************
+
+
+****************** Code 409 ******************
+\def\ttwide{0.7}% coefficient pour la largeur de composition
+\def\ttindent{5}% nombre de caract\xE8res d'indentation
+\hfill\vrule
+\vbox{%
+	\ttfamily% en TeX, on \xE9crirait "\tt"
+	\setbox0\hbox{0}% \wd0 est donc la largeur d'un caract\xE8re
+	\parindent=\ttindent\wd0 % r\xE9glage de l'indentation
+	\hsize=\ttwide\hsize % compose sur 70% de la largeur
+	Dans ce paragraphe, compos\xE9 en fonte \xE0 chasse fixe et o\xF9 les limites gauches
+	et droites du texte ont \xE9t\xE9 trac\xE9es, on constate que les caract\xE8res sont
+	exactement les uns au-dessous d'une ligne \xE0 l'autre. Des d\xE9bordements dans
+	la marge deviennent alors in\xE9vitables, car la largeur de composition (ici
+	\the\hsize) n'est pas un multiple de la largeur d'un caract\xE8re (\the\wd0 ),
+	le quotient des deux valant environ
+	\xdef\ttratio{\decdiv{\dimtodec\hsize}{\dimtodec\wd0 }}\ttratio.
+}%
+\vrule\hfill\null
+****************** Fin code ******************
+
+
+****************** Code 410 ******************
+Fonte normale : \fontname\font\par
+{\bf Fonte grasse : \fontname\font\par}
+{\it Fonte italique : \fontname\font\par}
+{\sc Fonte petites majuscules : \fontname\font}
+****************** Fin code ******************
+
+
+****************** Code 411 ******************
+\font\gras=LinLibertineTB-tlf-t1 at 8pt
+\font\ital= LinLibertineTI-tlf-t1 at 8pt
+\font\itgras=LinLibertineTBI-tlf-t1 at 8pt
+Du texte normal {\gras puis en gras, \ital en italique,
+\itgras en italique gras} et retour \xE0 la normale.
+****************** Fin code ******************
+
+
+****************** Code 412 ******************
+Code du caract\xE8re de coupure = \number\hyphenchar\font\par
+Caract\xE8re de coupure : "\char\hyphenchar\font"
+****************** Fin code ******************
+
+
+****************** Code 413 ******************
+\def\longtext{Voici une phrase \xE9crite avec des mots insignifiants mais terriblement,
+	\xE9pouvantablement, horriblement et ind\xE9niablement longs.}
+% cr\xE9\xE9r une macro restaurant le \hyphenchar
+\edef\restorehyphenchar{\hyphenchar\font=\number\hyphenchar\font}%
+
+%comportement normal, caract\xE8re de coupure "-"
+1) \vrule\vbox{\hsize=5cm \longtext}\vrule\hfill
+% modification du caract\xE8re de coupure "W"
+2) \vrule\vbox{\hsize=5cm \hyphenchar\font=`W \longtext}\vrule
+\medbreak
+% interdiction des coupures de mots
+3) \vrule\vbox{\hsize=5cm \hyphenchar\font=-1 \longtext}\vrule
+\restorehyphenchar
+****************** Fin code ******************
+
+
+****************** Code 414 ******************
+\def\longtext{Voici une phrase \xE9crite avec des mots insignifiants mais terriblement,
+	\xE9pouvantablement, horriblement et ind\xE9niablement longs.}
+
+\edef\restorehyphenchar{\hyphenchar\font=\number\hyphenchar\font}%
+\vrule\vbox{\hsize=5cm \hyphenchar\font=-1 \sloppy \longtext}\vrule
+\restorehyphenchar
+****************** Fin code ******************
+
+
+****************** Code 415 ******************
+a) \texttt{\number\hyphenchar\font}\qquad
+b) {\ttfamily\number\hyphenchar\font}
+****************** Fin code ******************
+
+
+****************** Code 416 ******************
+\leavevmode
+\vbox{%
+	\hsize=.4\hsize
+	\Souligne{Police \xE0 chasse variable}%
+	\vskip5pt 
+	espace inter-mot = \the\fontdimen2\font\par
+	\xE9trirement inter-mot = \the\fontdimen3\font\par
+	compression inter-mot = \the\fontdimen4\font
+}\hfill
+\vbox{%
+	\tt
+	\hsize=.4\hsize
+	\Souligne{Police \xE0 chasse fixe}%
+	\vskip5pt 
+	espace inter-mot = \the\fontdimen2\font\par
+	\xE9trirement inter-mot = \the\fontdimen3\font\par
+	compression inter-mot = \the\fontdimen4\font
+}
+****************** Fin code ******************
+
+
+****************** Code 417 ******************
+\def\ttwide{0.7}\def\ttindent{5}%
+\hfill\vrule
+\vbox{%
+	\ttfamily
+	\hyphenchar\font=`\- % change le caract\xE8re de coupure de la fonte en cours
+	\setbox0\hbox{0}\parindent=\ttindent\wd0 
+	\hsize=\ttwide\hsize % compose sur 70% de la largeur
+	Dans ce paragraphe, compos\xE9 en fonte \xE0 chasse fixe et o\xF9 les limites gauche
+	et droite du texte ont \xE9t\xE9 trac\xE9es, on constate que les caract\xE8res sont
+	exactement les uns au-dessous des autres d'une ligne \xE0 l'autre. Des d\xE9bordements
+	dans la marge deviennent in\xE9vitables m\xEAme si les coupures des mots sont
+	\xE0 nouveau rendues possibles.%
+}%
+\vrule\hfill\null
+****************** Fin code ******************
+
+
+****************** Code 418 ******************
+\frboxsep=0.5pt 
+\def\printallchars{%
+	\leavevmode
+	\for\xx=0 to255\do{%
+		\vbox{% empiler verticalement
+			\offinterlineskip% en d\xE9sactivant le ressort d'interligne
+			\setbox0\hbox{\frbox{\char\xx}}%
+			\copy0 % la boite contenant le caract\xE8re encadr\xE9
+			\kern1pt% saute 1pt vertical
+			\hbox to\wd0{\hss$\scriptscriptstyle\xx$\hss}% le num\xE9ro
+		}\hskip0.5em plus1pt minus1pt % saute 0.5em horizontalement
+	}%
+}
+\tt
+Nom de la fonte = \fontname\font\par
+\printallchars
+****************** Fin code ******************
+
+
+****************** Code 419 ******************
+\setbox0=\hbox{\tt\char23}
+Largeur = \the\wd0 \qquad Hauteur = \the\ht0 \qquad Profondeur = \the\dp0 
+****************** Fin code ******************
+
+
+****************** Code 420 ******************
+{\tt\xdef\nfont{\the\font}}
+Largeur = \the\fontcharwd\nfont23 \qquad Hauteur = \the\fontcharht\nfont23 
+\qquad Profondeur = \the\fontchardp\nfont23
+****************** Fin code ******************
+
+
+****************** Code 421 ******************
+\newmacro\ttstart[5]{%
+	\begingroup
+	\tt
+	\edef\restorefontsettings{% stocke les param\xE8tres de fonte
+		\hyphenchar\font=\the\hyphenchar\font\relax% le \hyphenchar
+		\fontdimen2\font=\the\fontdimen2\font\relax% et les param\xE8tres d'espacement
+		\fontdimen3\font=\the\fontdimen3\font\relax
+		\fontdimen4\font=\the\fontdimen4\font\relax
+	}%
+	\fontdimen3\font=0.30\fontdimen2\font% composante + = 30% de la dimension naturelle
+	\fontdimen4\font=0.20\fontdimen2\font% composante - = 20% de la dimension naturelle
+	\hyphenchar\font=`\- % on autorise la coupure des mots (au cas o\xF9 on utilise latex)
+	\setbox0\hbox{0}% largeur d'un caract\xE8re
+	\parindent=#1\wd0 % indentation (en nombre de caract\xE8res)
+	\ignorespaces
+}
+\def\ttstop{%
+	\restorefontsettings% restaure les param\xE8tres de fonte
+	\endgroup% et ferme le groupe
+}
+\hfill\vrule
+\def\ttwide{0.70}%
+\vbox{%
+	\hsize=\ttwide\hsize % compose sur 70% de la largeur
+	\ttstart[5]
+	Dans ce paragraphe, compos\xE9 en fonte \xE0 chasse fixe et o\xF9 les limites gauche
+	et droite du texte ont \xE9t\xE9 trac\xE9es, on constate que les caract\xE8res ne sont pas
+	exactement les uns au-dessous des autres entre les lignes du paragraphe.
+	Puisque les espaces sont redevenus \xE9tirables, les d\xE9bordements dans la marge
+	(m\xEAme s'ils restent possibles), sont bien plus rares et ce d'autant plus que
+	le nombre d'espaces dans une ligne est grand.%
+	\ttstop
+}%
+\vrule\hfill\null
+****************** Fin code ******************
+
+
+****************** Code 422 ******************
+\catcode`\@11
+\newcount\brktt at cnt
+\newdimen\brktt at interletter
+\newif\ifline at start% bool\xE9en vrai lorsqu'aucun caract\xE8re n'est encore affich\xE9
+\newif\if at indivifound% bool\xE9en qui sera vrai si un motif sp\xE9cial est rencontr\xE9
+
+\def\insert at blankchar{%
+	\ifstarred\insert at blankchar@ii\insert at blankchar@i
+}
+
+\def\insert at blankchar@i#1{% ins\xE8re une espace de largeur #1 caract\xE8res complets
+	\ifnum\numexpr#1\relax>0
+		\kern\numexpr#1\relax\dimexpr\ttchar at width+\brktt at interletter\relax
+	\fi
+}
+
+\def\insert at blankchar@ii#1{% ins\xE8re #1-1 caract\xE8res complets + 1 largeur de caract\xE8re
+	\ifnum\numexpr#1\relax>0
+		\insert at blankchar@i{#1-1}\kern\ttchar at width
+	\fi
+}
+
+\def\restart at hbox#1{%
+	\egroup% feerme la \hbox pr\xE9c\xE9dente
+	\hbox\bgroup% ouvre la suivante
+	\expsecond{\def\tt at remaintext}
+		{\romannumeral\removefirstspaces at i{#1}}% initialiser le code \xE0 composer
+	\let\previous at char\space% initialise le caract\xE8re pr\xE9c\xE9dent
+	\line at starttrue% aucun caract\xE8re n'a encore \xE9t\xE9 imprim\xE9
+	\brktt at cnt=0\relax% remettre le compteur \xE0 0
+}
+
+\newmacro\breaktt[0.3em][\hsize]1{%
+% arg optionnel #1 et #2 = ressorts inter-lettre et dimension horizontale texte
+% #3 = texte \xE0 espacer
+	\begingroup% ouvrir un groupe et le fermer \xE0 la toute fin
+	\par% commencer un nouveau paragraphe -> passage en mode vertical
+	\parindent=0pt% emp\xEAche l'indentation
+	\tt% passer en fonte \xE0 chasse fixe
+	\setbox0 = \hbox{M}% la boite 0 contient un caract\xE8re
+	\edef\ttchar at width{\the\wd0 }% largeur de chaque caract\xE8re en fonte \tt
+	\edef\text at width{\the\dimexpr#2\relax}% largeur de composition
+	% les 2 lignes suivantes rendent le compteur \xE9gal \xE0 E((L-l)/(l+Delta))
+	\brktt at cnt=\numexpr\dimexpr#2-\wd0 \relax\relax% largeur diminu\xE9e du 1er caract\xE8re
+	\divide\brktt at cnt by \numexpr\dimexpr\wd0 + #1 \relax\relax
+	% le nombre de caract\xE8re par ligne est \xE9gal \xE0 1 de plus :
+	\edef\maxchar at num{\number\numexpr\brktt at cnt+1\relax}%
+	% calcul de la dimension inter-lettre
+	\brktt at interletter=\dimexpr(\text at width-\ttchar at width*\maxchar at num)/\brktt at cnt\relax
+	% stocke le texte apr\xE8s avoir enlev\xE9 les \xE9ventuels espaces extremes :
+	\expsecond{\expsecond{\def\tt at remaintext}}{\removetrailspaces{#3}}%
+	\unless\ifx\tt at remaintext\empty% si le texte \xE0 composer n'est pas vide
+		\hbox\bgroup% d\xE9marrer la boite horizontale contenant la premi\xE8re ligne
+		\insert at blankchar\ttindent% ins\xE9rer une espace d'indentation
+		\brktt at cnt=\ttindent\relax% tenir compte du nombre de caract\xE8res indent\xE9s
+		\line at starttrue% il s'agit du d\xE9but d'une ligne
+		\expandafter\breaktt at i% aller \xE0 la macro r\xE9cursive
+	\fi
+}
+
+\def\breaktt at i{%
+	\print at nchar\maxchar at num% afficher \maxchar at num caract\xE8res
+	\ifx\tt at remaintext\empty% si texte restant est vide
+		\egroup% fermer la hbox
+		\par% aller \xE0 la ligne
+		\endgroup% fermer le groupe ouvert au d\xE9but
+	\else
+		\unless\ifnum\brktt at cnt<\maxchar at num\relax% si la ligne est remplie
+			\exparg\restart at hbox{\tt at remaintext}% ferme la hbox et en r\xE9-ouvre une
+		\fi
+		\expandafter\breaktt at i% enfin, continuer le processus
+ 	\fi
+}
+
+\def\print at nchar#1{% affiche #1 caract\xE8res pris dans \tt at remaintext
+	\for\xxx= 1 to #1 \do 1{%
+		\ifx\tt at remaintext\empty% si le code restant \xE0 composer est vide
+			\exitfor\xxx%sortir de la boucle pr\xE9matur\xE9ment
+		\else
+			\@indivifoundfalse% sinon, a priori, les motifs de ligature ne sont pas trouv\xE9s
+			% pour chaque \indivi at tmp dans la liste de ligatures
+			\expsecond{\doforeach\indivi at tmp\in}{\liglist}%
+				{% si le code commence par la ligature courante
+				\exptwoargs\ifstartwith\tt at remaintext\indivi at tmp
+					{\let\previous at char\indivi at tmp% prendre le motif pour caract\xE8re courant,
+					\expsecond{\rightofsc\tt at remaintext}{\indivi at tmp}% l'enlever du texte restant
+					\@indivifoundtrue% marquer qu'un motif a \xE9t\xE9 trouv\xE9
+					\doforeachexit% et sortir pr\xE9matur\xE9ment de la boucle
+					}%
+					{}% si le code ne commence pas le motif courant -> ne rien faire
+				}%
+			\unless\if at indivifound% si aucun motif trouv\xE9,
+				\grab at first\tt at remaintext\previous at char%  lire le premier caract\xE8re
+			\fi
+			\advance\brktt at cnt by 1 % incr\xE9menter le compteur de caract\xE8res
+			\hbox to\ttchar at width{\hss\previous at char\hss}% afficher le caract\xE8re lu
+			\line at startfalse% nous ne sommes plus au d\xE9but d'une ligne
+			\ifnum\brktt at cnt<\maxchar at num\relax% si la ligne n'est pas encore remplie
+				\kern\brktt at interletter% ins\xE9rer le ressort inter-lettre
+			\else
+				\exitfor\xxx% sinon, sortir de la boucle pr\xE9matur\xE9ment
+			\fi
+		\fi
+	}%
+}
+\catcode`\@12
+
+\def\liglist{<<,>>}% liste des motifs de ligature
+                   % ajouter \xE0, \xE9, etc si codage UTF8 + moteur 8 bits
+\def\ttindent{3}% valeur de l'indentation'
+\vrule\vbox{\breaktt[4pt][.7\hsize]{%
+Dans ce paragraphe, compos\xE9 en fonte \xE0 chasse fixe et o\xF9 les limites gauche
+et droite du texte ont \xE9t\xE9 trac\xE9es, on constate que les caract\xE8res sont
+exactement les uns au-dessous des autres d'une ligne \xE0 l'autre. Plus aucun
+d\xE9bordement n'a lieu, car une espace correctement calcul\xE9e est ins\xE9r\xE9e entre
+chaque caract\xE8re. Les mots, en revanche, sont toujours coup\xE9s <<sauvagement>>.%
+}%
+}\vrule\smallbreak
+
+\vrule\vbox{\breaktt[1pt][6cm]{%
+Dans ce paragraphe, compos\xE9 en fonte \xE0 chasse fixe et o\xF9 les limites gauche
+et droite du texte ont \xE9t\xE9 trac\xE9es, on constate que les caract\xE8res sont
+exactement les uns au-dessous des autres d'une ligne \xE0 l'autre. Plus aucun
+d\xE9bordement n'a lieu, car une espace correctement calcul\xE9e est ins\xE9r\xE9e entre
+chaque caract\xE8re. Les mots, en revanche, sont toujours coup\xE9s <<sauvagement>>.%
+}%
+}\vrule
+****************** Fin code ******************
+
+
+****************** Code 423 ******************
+\catcode`\@11
+\newcount\brktt at cnt
+\newdimen\brktt at interletter
+\newif\ifline at start% bool\xE9en vrai lorsqu'aucun caract\xE8re n'est encore affich\xE9
+\newif\if at indivifound% bool\xE9en qui sera vrai si un motif sp\xE9cial est rencontr\xE9
+
+\newmacro\breakttA[0.3em][\hsize]1{%
+% arg optionnel #1 et #2 = ressorts inter-lettre et dimension horizontale texte
+% #3 = texte \xE0 espacer
+	\begingroup% ouvrir un groupe et le fermer \xE0 la toute fin
+	\par% commencer un nouveau paragraphe -> passage en mode vertical
+	\parindent=0pt% emp\xEAche l'indentation
+	\tt% passer en fonte \xE0 chasse fixe
+	\setbox0 = \hbox{M}% la boite 0 contient un caract\xE8re
+	\edef\ttchar at width{\the\wd0 }% largeur de chaque caract\xE8re en fonte \tt
+	\edef\text at width{\the\dimexpr#2\relax}% largeur de composition
+	% les 2 lignes suivantes rendent le compteur \xE9gal \xE0 E((L-l)/(l+Delta))
+	\brktt at cnt=\numexpr\dimexpr#2-\wd0 \relax\relax% largeur diminu\xE9e du 1er caract\xE8re
+	\divide\brktt at cnt by \numexpr\dimexpr\wd0 + #1 \relax\relax
+	% le nombre de caract\xE8res par ligne est \xE9gal \xE0 1 de plus :
+	\edef\maxchar at num{\number\numexpr\brktt at cnt+1\relax}%
+	% calcul de la dimension inter-lettre
+	\brktt at interletter=\dimexpr(\text at width-\ttchar at width*\maxchar at num)/\brktt at cnt\relax
+	% stocke le texte apr\xE8s avoir enlev\xE9 les \xE9ventuels espaces extremes :
+	\expsecond{\expsecond{\def\tt at remaintext}}{\removetrailspaces{#3}}%
+	\unless\ifx\tt at remaintext\empty% si le texte \xE0 composer n'est pas vide
+		\hbox\bgroup% d\xE9marrer la boite horizontale contenant la premi\xE8re ligne
+		\insert at blankchar\ttindent% ins\xE9rer une espace d'indentation
+		\brktt at cnt=\ttindent\relax% tenir compte du nombre de caract\xE8res indent\xE9s
+		\line at starttrue% il s'agit du d\xE9but d'une ligne
+		\expandafter\breakttA at i% aller \xE0 la macro r\xE9cursive
+	\fi
+}
+
+\def\breakttA at i{%
+	\edef\remaining at chars{% calculer le nombre de caract\xE8res restant \xE0 placer sur la ligne
+		\numexpr\maxchar at num-\brktt at cnt\relax}%
+	\len at tonextword% \next at len contient le nombre de caract\xE8res du prochain mot
+	% si le mot + l'eventuel "-" qui le suit ne peut pas loger sur la ligne en cours
+	\ifnum\numexpr\next at len+\extra at char\relax>\remaining at chars\relax
+		\ifline at start% et si c'est le d\xE9but d'une ligne
+			% avertir l'utilisateur
+			\message{Largeur de composition trop faible pour
+				\unexpanded\expandafter{\next at word}^^J}%
+			% et composer tout de m\xEAme "\xE0 la sauvage" jusqu'\xE0 la fin de la ligne
+			\exparg\print at nchar{\number\numexpr\maxchar at num-\brktt at cnt}%
+		\else% si la ligne en cours n'est pas au d\xE9but
+			\insert at blankchar*{\maxchar at num-\brktt at cnt}% remplir la ligne d'espaces
+		\fi
+		\exparg\restart at hbox{\tt at remaintext}% commencer une nouvelle ligne
+		\expandafter\breakttA at i% et poursuivre le processus
+	% s'il y a assez de place pour accueillir ce qui est avant la prochaine coupure
+	\else
+		\print at nchar\next at len% afficher le mot
+		\ifx\tt at remaintext\empty% si texte restant est vide
+			\insert at blankchar*{\maxchar at num-\brktt at cnt}% remplir la ligne
+			\egroup% fermer la hbox en cours
+			\par% aller \xE0 la ligne
+			\endgroup% fermer le groupe ouvert au d\xE9but. Fin du processus
+		\else% si le texte restant n'est pas vide
+			\ifnum\brktt at cnt<\maxchar at num\relax% si la ligne n'est pas remplie
+					\print at nchar{1}% afficher le caract\xE8re qui suit le mot (" " ou "-")
+			\else% si la ligne est remplie
+				\exparg\restart at hbox{\tt at remaintext}% ferme la hbox et en r\xE9-ouvre une
+			\fi
+			\expandafter\expandafter\expandafter\breakttA at i% enfin, continuer le processus
+		\fi
+	\fi
+}
+
+\def\leftofsc#1#2{% dans la macro #1, garde ce qui est \xE0 gauche de #2
+	\def\leftofsc at i##1#2##2\@nil{\def#1{##1}}%
+	\expandafter\leftofsc at i#1#2\@nil
+}
+
+\def\len at tonextword{% stocke dans \next at len le nombre de caract\xE8res avant
+                    % le prochain point de coupure dans \tt at remaintext
+	\let\next at word\tt at remaintext% copie \tt at remaintext dans la macro temporaire \next at word
+	\leftofsc\next at word{ }% ne prend que ce qui est avant le prochain espace
+	\exparg\ifin\next at word{-}% si le mot contient un tiret
+		{\leftofsc\next at word{-}% prendre ce qui est \xE0 gauche de ce tiret
+		\def\extra at char{1}% il y a un caract\xE8re de plus \xE0 loger apr\xE8s le mot
+		}% sinon, le caract\xE8re apr\xE8s le mot est un espace
+		{\def\extra at char{0}% qu'il ne faut pas compter
+		}%
+	\setbox0=\hbox{\next at word}% enfermer le mot dans une boite
+	% et en calculer le nombre de caract\xE8res = dim(boite)/dim(caract\xE8re)
+	\edef\next at len{\number\numexpr\dimexpr\wd0 \relax/\dimexpr\ttchar at width\relax\relax}%
+}
+\catcode`\@12
+
+\def\liglist{<<,>>}% liste des motifs de ligature (mettre \xE0, \xE9, etc si codage UTF8)
+\def\ttindent{3}
+
+\vrule\vbox{\breakttA[3pt][8cm]{%
+Dans ce paragraphe, compos\xE9 en fonte \xE0 chasse fixe et o\xF9 les limites gauche
+et droite du texte ont \xE9t\xE9 trac\xE9es, on constate que les caract\xE8res sont
+exactement les uns au-dessous d'une ligne \xE0 l'autre. Plus aucun d\xE9bordement
+n'a lieu, car une espace correctement calcul\xE9e est ins\xE9r\xE9e entre chaque
+caract\xE8re. Dor\xE9navant, les mots ne sont plus coup\xE9s <<~sauvagement~>>.
+}}\vrule\medbreak
+
+\leavevmode\vrule\vbox{\breakttA[1pt][5cm]{%
+Dans ce paragraphe, compos\xE9 en fonte \xE0 chasse fixe et o\xF9 les limites gauche
+et droite du texte ont \xE9t\xE9 trac\xE9es, on constate que les caract\xE8res sont
+exactement les uns au-dessous d'une ligne \xE0 l'autre. Plus aucun d\xE9bordement
+n'a lieu, car une espace correctement calcul\xE9e est ins\xE9r\xE9e entre chaque
+caract\xE8re. Dor\xE9navant, les mots ne sont plus coup\xE9s <<~sauvagement~>>.
+}}\vrule\qquad\def\ttindent{0}%
+\vrule\vbox{\breakttA[0.6pt][2cm]{mot-compos\xE9 mot-cl\xE9 passe-droit au-dessus
+l\xE0-bas remonte-pente vingt-huit Notre-Dame-de-Lourdes Mont-Blanc
+Saint-Jean-de-Luz}}\vrule
+****************** Fin code ******************
+
+
+****************** Code 424 ******************
+\newmacro\zerocompose[]2{%
+% #1=code \xE0 ex\xE9cuter avant la composition
+% #2=registre de boite recevant le r\xE9sultat
+% #3= texte \xE0 composer en largeur 0pt
+	\setbox#2=\vbox{%
+		#1% code a ex\xE9cuter (changement de fonte par exemple)
+		\hfuzz=\maxdimen% annule les avertissements pour d\xE9bordement horizontaux
+		\hbadness=10000 % annule les avertissements pour mauvaise boite horizontale
+		\pretolerance=-1 % d\xE9sactive la premi\xE8re passe (celle sans coupures)
+		\tolerance=10000 % passe avec coupures accept\xE9e
+		\hyphenpenalty=-10000 % favorise fortement les copures de mots
+		\lefthyphenmin=2 \righthyphenmin=3 % longueur mini des fragments de d\xE9but et fin
+		\clubpenalty=0 % pas de p\xE9nalit\xE9 suppl\xE9mentaire apr\xE8s la premi\xE8re ligne
+		\interlinepenalty=0 % pas de p\xE9nalit\xE9 inter-ligne
+		\widowpenalty=0 % pas de p\xE9nalit\xE9 suppl\xE9mentaire avant la derni\xE8re ligne
+		\exhyphenpenalty=0 % ne pas p\xE9naliser une coupure explicite
+		\leftskip=0pt \rightskip=0pt % d\xE9sactive les \xE9ventuels ressorts lat\xE9raux
+		\everypar={}% d\xE9sactive l'\xE9ventuel \everypar
+		\parfillskip=0pt plus1fil % r\xE8gle le \parfillskip par d\xE9faut
+		\hsize=0pt % largeur de composition = 0pt
+		\edef\restorehyphenchar{\hyphenchar\font=\number\hyphenchar\font}%
+		\hyphenchar\font=`\- % impose "-" comme caract\xE8re de coupure
+		\noindent % pas d'indentation + passage en mode horizontal
+		\hskip0pt \relax% premier noeud horizontal pour permettre la coupure de la suite
+		#3\par% compose #3
+		\restorehyphenchar% restaure le caract\xE8re de coupure
+		}%
+}
+\zerocompose{0}{Programmation}%
+\leavevmode\box0 
+\hskip 5cm 
+\zerocompose{0}{Composer en largeur nulle}%
+\box0 
+****************** Fin code ******************
+
+
+****************** Code 425 ******************
+\def\dummytext{Ceci est un texte sans aucun int\xE9r\xEAt dont le seul but est de meubler
+		la page de fa\xE7on artificielle. }
+\setbox0=\vtop{% d\xE9finit la boite 0
+	\hsize=8cm 
+	\dummytext\dummytext
+}
+
+a) Boite pleine : \copy0 
+
+b) \setbox0=\vtop{%
+	\unvbox0 % boite pr\xE9c\xE9demment compos\xE9e
+	\global\setbox1=\lastbox% et capture la derni\xE8re ligne dans la boite 1
+	}%
+	Derni\xE8re ligne = |\hbox{\unhbox1 }|\par% redonne \xE0 box1 sa largeur naturelle
+	Boite restante = \box0
+****************** Fin code ******************
+
+
+****************** Code 426 ******************
+\def\dummytext{Ceci est un texte sans aucun int\xE9r\xEAt dont le seul but est de meubler
+		la page de fa\xE7on artificielle. }
+\setbox0=\vtop{% d\xE9finit la boite 0
+	\hsize=8cm 
+	\dummytext\dummytext
+}
+
+\setbox0=\vtop{\unvbox0 \global\setbox1=\lastbox}
+\setbox1=\hbox{\unhbox1 }
+1) |\box1|
+
+\setbox0=\vtop{\unvbox0 \global\setbox1=\lastbox}
+\setbox1=\hbox{\unhbox1 }
+2) |\box1|
+
+\setbox0=\vtop{\unvbox0 \global\setbox1=\lastbox}
+\setbox1=\hbox{\unhbox1 }
+3) |\box1|
+****************** Fin code ******************
+
+
+****************** Code 427 ******************
+\setbox0=\vbox{\hsize=2.5cm Programmer en TeX est facile}%
+\showboxbreadth=5 \showboxdepth=3 \tracingonline=1 
+\showbox0 
+****************** Fin code ******************
+
+
+****************** Code 428 ******************
+\newbox\tempbox
+\def\reversebox#1{% affiche le contenu de la boite verticale #1
+	\setbox#1=\vbox{%
+		\unvbox#1% composer la boite #1
+		\unskip\unpenalty% retirer ce qui n'est pas capturable par \lastbox
+		\global\setbox0=\lastbox% la boite 1 devient la derni\xE8re ligne
+	}%
+	|\hbox{\unhbox0 }|\par% afficher la boite 1 dans sa largeur d'origine
+	\ifvoidorempty{#1}% si le registre #1 contient une boite vide
+		\relax% ne rien faire
+		{\reversebox{#1}}% sinon, rencommencer
+}
+\def\dummytext{Ceci est un texte sans aucun int\xE9r\xEAt dont le seul but est de meubler
+		la page de fa\xE7on artificielle. }
+\setbox\tempbox=\vbox{% d\xE9finit la boite 0
+	\hsize=8cm \dummytext\dummytext
+}
+
+\reversebox\tempbox
+****************** Fin code ******************
+
+
+****************** Code 429 ******************
+% compose "Programmation" en largeur 0 dans la boite 0 :
+\zerocompose{0}{Programmation}%
+Boite initiale : \copy0 \par% compose la boite r\xE9sultante
+\vfuzz=\maxdimen% annule les avertissements pour d\xE9bordements
+\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1 =\vsplit0 to 0pt % coupe la boite 0 \xE0 0pt
+{% dans un groupe (o\xF9 la boite 0 sert de brouillon)
+	\setbox0 =\vbox{% affecter \xE0 la boite brouillon
+		\unvbox1 % la boite 1 compos\xE9e dans sa largeur naturelle
+		\unskip\unpenalty% annule ce qui n'est pas une boite
+		\global\setbox2 =\lastbox% affecte globalement la derni\xE8re (et unique) ligne
+		                         % \xE0 la boite 1
+	}%
+}% ferme le groupe
+\setbox2=\hbox{\unhbox2}% rend \xE0 la boite 2 sa largeur naturelle
+Premi\xE8re ligne = "\box2 "% compose la boite 2
+****************** Fin code ******************
+
+
+****************** Code 430 ******************
+\catcode`@11
+\def\hyphlengths#1#2{%#2 = macro contenant les longueurs de coupures du mot #1
+	\begingroup
+		\zerocompose
+			[\tt% passer en fonte \xE0 chasse fixe
+			\setbox\z@\hbox{M}\xdef\ttwidth{\the\wd\z@}% mesurer la largeur des caract\xE8res
+			]\z@{#1}% compose en 0pt dans la boite 0
+		\let#2 = \empty% initialise la macro #2
+		\def\cumul at length{0}% le cumul des longueurs initialis\xE9 \xE0 0
+		\vfuzz=\maxdimen% annule les avertissements pour d\xE9bordement
+		\splittopskip=\z@ % ne rajouter aucun espace au sommet de la boite restante
+		\loop
+			\setbox1=\vsplit\z@ to \z@% couper la boite \xE0 0pt de hauteur
+			{\setbox\z@=\vbox{\unvbox1 \unskip\unpenalty\global\setbox1=\lastbox}}%
+			\setbox1=\hbox{\unhbox1 }%
+			\unless\ifvoid\z@% si la boite 0 n'est pas encore vide
+				\edef\cumul at length{% mettre \xE0 jour \cumul at length
+					\number\numexpr
+						\cumul at length
+						+% ajouter le quotient "largeur syllabe/largeur d'1 caract\xE8re"
+						\wd1/\dimexpr\ttwidth\relax
+						-1% et soustraire 1 (le caract\xE8re "-")
+						\relax
+				}%
+				% ajouter \xE0 #2 la virgule et le cumul actuel +1
+				\edef#2{% d\xE9finir la macro #2 :
+					#2% reprendre le contenu de #2
+					\ifx#2\empty\else,\fi% ajouter "," si #2 non vide
+					\number\numexpr\cumul at length+1\relax% et le cumul
+					}%
+		\repeat% et recommencer
+		\expsecond{% avant de fermer le groupe
+	\endgroup
+	\def#2}{#2}% d\xE9finit #2 hors du groupe
+}
+\catcode`\@12
+a) \hyphlengths{programmation}\foo liste = "\foo"\par
+b) \hyphlengths{typographie}\foo liste ="\foo"\par
+c) \hyphlengths{j'entendrai}\foo liste ="\foo"\par
+d) \hyphlengths{vite}\foo liste ="\foo"
+****************** Fin code ******************
+
+
+****************** Code 431 ******************
+\catcode`\@11
+\newcount\brktt at cnt
+\newdimen\brktt at interletter
+\newif\ifline at start% bool\xE9en vrai lorsqu'aucun caract\xE8re n'est encore affich\xE9
+\newif\if at indivifound% bool\xE9en qui sera vrai si un motif sp\xE9cial est rencontr\xE9
+
+\let\breakttB=\breakttA
+
+\def\breakttA at i{%
+	\edef\remaining at chars{% calculer le nombre de caract\xE8res restant \xE0 placer sur la ligne
+		\numexpr\maxchar at num-\brktt at cnt\relax}%
+	\len at tonextword% calculer dans \next at len le nombre de caract\xE8res avant le prochain mot
+	\def\next at hyphlen{0}% initialiser la longueur de coupure possible du mot
+	% si le mot + l'eventuel "-" qui le suit ne rentre pas sur ce qui reste de la ligne
+	\ifnum\numexpr\next at len+\extra at char\relax>\remaining at chars\relax
+		\hyphlengths\next at word\list at hyphlengths% b\xE2tir la liste des longueurs de coupures
+		\unless\ifx\list at hyphlengths\empty% si une coupure est possible
+			\expsecond{\doforeach\xx\in}{\list at hyphlengths}% les examiner toutes
+				{% si la coupure examin\xE9e peut loger sur la ligne
+				\unless\ifnum\xx>\remaining at chars\relax%
+					\let\next at hyphlen\xx% la stocker
+				\fi% pour que \next at hyphlen soit maximal
+				}%
+		\fi
+	\fi
+	\ifnum\next at hyphlen>0 % si une coupure est n\xE9cessaire et a \xE9t\xE9 trouv\xE9e
+		\let\next at len\next at hyphlen% mettre \xE0 jour la longueur du mot \xE0 placer
+	\fi
+	% si le mot + l'eventuel "-" qui le suit ne peut pas loger sur la ligne en cours
+	\ifnum\numexpr\next at len+\extra at char\relax>\remaining at chars\relax
+		\ifline at start% si c'est le d\xE9but d'une ligne
+			% avertir l'utilisateur
+			\message{Largeur de composition trop faible pour
+				 \unexpanded\expandafter{\next at word}^^J}%
+			% et composer tout de m\xEAme jusqu'\xE0 la fin de la ligne
+			\exparg\print at nchar{\number\numexpr\maxchar at num-\brktt at cnt}%
+		\else% sinon
+			\insert at blankchar*{\maxchar at num-\brktt at cnt}% remplir la ligne
+		\fi
+		\exparg\restart at hbox{\tt at remaintext}% r\xE9-ouvrir une boite
+		\expandafter\breakttA at i% et poursuivre le processus
+	% s'il y a la place pour accueillir ce qui est avant la prochaine coupure
+	\else
+		\ifnum\next at hyphlen>0 % si une coupure de mot doit \xEAtre faite
+			\exparg\print at nchar{\number\numexpr\next at len-1}% afficher les lettres de la syllabe
+			\print at hyphchar% et le caract\xE8re de coupure
+			\insert at blankchar*{\maxchar at num-\brktt at cnt}% remplir la ligne
+			\exparg\restart at hbox{\tt at remaintext}% r\xE9-ouvrir une boite
+			\expandafter\expandafter\expandafter\breakttA at i% et continuer le processus
+		\else% si pas de coupure dans le mot
+			\print at nchar\next at len% afficher le mot
+			\ifx\tt at remaintext\tt at emptytext% si texte restant est vide
+				\insert at blankchar*{\maxchar at num-\brktt at cnt}% remplir la ligne
+				\egroup% fermer la hbox
+				\par% aller \xE0 la ligne
+				\endgroup% fermer le groupe ouvert au d\xE9but. Fin du processus
+			\else% si le texte restant n'est pas vide
+				\ifnum\brktt at cnt<\maxchar at num\relax% si la ligne n'est pas remplie
+						\print at nchar{1}% afficher le caract\xE8re qui suit le mot
+				\else% si la ligne est remplie
+					\exparg\restart at hbox{\tt at remaintext}% ferme la hbox et en r\xE9-ouvre une
+				\fi
+				\expandafter\expandafter\expandafter\breakttA at i% enfin, continuer le processus
+			\fi
+		\fi
+	\fi
+}
+
+\def\print at hyphchar{%
+	\advance\brktt at cnt by 1 % augmenter le compteur de caract\xE8res
+	\hbox to\ttchar at width{\hss-\hss}% afficher "-"
+	\ifnum\brktt at cnt<\maxchar at num\relax% si la ligne n'est pas encore remplie
+		\kern\brktt at interletter\relax% ins\xE9rer le ressort inter-lettre
+	\fi
+}
+
+\catcode`\@12
+
+\def\liglist{<<,>>}% liste des motifs de ligature (mettre \xE0, \xE9, etc si codage UTF8)
+\def\ttindent{3}
+
+\vrule\vbox{\breakttB[3pt][8cm]{%
+Dans ce paragraphe, compos\xE9 en fonte \xE0 chasse fixe et o\xF9 les limites gauche
+et droite du texte ont \xE9t\xE9 trac\xE9es, on constate que les caract\xE8res sont
+exactement les uns au-dessous d'une ligne \xE0 l'autre. Plus aucun d\xE9bordement
+n'a lieu, car une espace correctement calcul\xE9e est ins\xE9r\xE9e entre chaque
+caract\xE8re. Dor\xE9navant, les mots ne sont plus coup\xE9s <<sauvagement>>.
+}%
+}\vrule
+
+\vrule\vbox{\breakttB[1pt][5cm]{%
+Dans ce paragraphe, compos\xE9 en fonte \xE0 chasse fixe et o\xF9 les limites gauche
+et droite du texte ont \xE9t\xE9 trac\xE9es, on constate que les caract\xE8res sont
+exactement les uns au-dessous d'une ligne \xE0 l'autre. Plus aucun d\xE9bordement
+n'a lieu, car une espace correctement calcul\xE9e est ins\xE9r\xE9e entre chaque
+caract\xE8re. Dor\xE9navant, les mots ne sont plus coup\xE9s <<sauvagement>>.
+}%
+}\vrule
+****************** Fin code ******************
+
+
+****************** Code 432 ******************
+Voici un algorithme \xE9l\xE9mentaire :
+\algorithm[\#]{Algorithme {\bf MinMax}}|
+macro ~Min_Max~ (#1) % afficher la valeur max et min d'une liste de valeurs #1
+	$V_{max}:=-\infty$ % $-\infty$ ou la plus petite valeur possible
+	$V_{min}:=+\infty$ % $+\infty$ ou la plus grande valeur possible
+	~Pour~ chaque $x$ dans (#1)
+		~Si~ $x>V_{max}$
+			~alors~ $V_{max}:=x$
+		~FinSi~
+		~Si~ $x<V_{min}$
+			~alors~ $V_{min}:=x$
+		~FinSi~
+	~FinPour~
+	Afficher "$V_{min}$ et $V_{max}$"
+~FinMin_Max~|
+Suite du texte...
+****************** Fin code ******************
+
+
+****************** Code 433 ******************
+\def\algoindent{1cm}%
+\begingroup
+\parindent=0pt % pas d'indentation
+\defactive\^^M{\leavevmode\par}% rend le retour charriot actif
+\defactive\^^I{\hskip\algoindent\relax}% tabulation active
+Pas d'indentation ici\ldots
+	Voici une premi\xE8re ligne
+		une seconde plus indent\xE9e
+	retour \xE0 l'indentation normale
+		\for\xx=1to10\do{un long texte }
+	pour terminer, la derni\xE8re ligne
+\endgroup
+****************** Fin code ******************
+
+
+****************** Code 434 ******************
+\def\algoindent{1cm}%
+\begingroup
+\leftskip=0pt \rightskip=0pt plus1fil \relax % initialise les ressorts lat\xE9raux
+\parindent=0pt % pas d'indentation
+\defactive\^^M{\leavevmode\par\leftskip=0pt }% rend le retour charriot actif
+\defactive\^^I{\advance\leftskip by \algoindent\relax}% tabulation active
+Pas d'indentation ici\ldots
+	Voici une premi\xE8re ligne
+		une seconde plus indent\xE9e
+	retour \xE0 l'indentation normale
+		\for\xx=1to10\do{un long texte }
+	pour terminer, la derni\xE8re ligne
+\endgroup
+****************** Fin code ******************
+
+
+****************** Code 435 ******************
+ % compteur de lignes pour l'algorithme
+\def\algoindent{1cm}%
+\begingroup
+\algocnt=1 % initialise le compteur \xE0 1
+\leftskip=0pt \rightskip=0pt plus1fil\relax% initialise les ressorts \xE0 0pt
+\parindent=0pt % pas d'indentation
+\everypar={\llap{$\scriptstyle\number\algocnt$\kern\dimexpr4pt+\leftskip\relax}}%
+
+\defactive\^^M{\leavevmode\par\advance\algocnt by1 \leftskip=0pt }% retour charriot actif
+\defactive\^^I{\advance\leftskip by \algoindent\relax}% tabulation active
+Pas d'indentation ici\ldots
+	Voici une premi\xE8re ligne
+		une seconde plus indent\xE9e
+	retour \xE0 l'indentation normale
+		\for\xx=1to10\do{un long texte }
+	pour terminer, la derni\xE8re ligne
+\endgroup
+****************** Fin code ******************
+
+
+****************** Code 436 ******************
+\newif\ifnumalgo
+\newcount\algocnt
+\numalgotrue
+
+\def\algoindent{2em}
+\def\algorule{.4pt}% \xE9paisseur des r\xE9glures de d\xE9but et de fin
+
+\def\algohrulefill{% remplit avec une ligne horizontale
+	\leavevmode
+	\leaders\hrule height\algorule\hfill
+	\kern0pt % rajoute un noeud au cas o\xF9 la commande est en fin de ligne
+}
+
+\newmacro\algorithm[\\,\#,\{,\}]2{%
+	\medbreak
+	\begingroup% ouvre un groupe (sera ferm\xE9 \xE0 la fin de l'algorithme)
+		\algocnt=1 % initialise le compteur de lignes
+		\leftskip=0pt \rightskip=0pt plus1fil\relax% initialise les ressorts lat\xE9raux
+		\parindent=0pt % pas d'indentation
+		%%%%%%%%%%%% affichage du titre %%%%%%%
+		\algohrulefill% remplir avec une ligne horizontale
+		\ifempty{#2}% si #2 est vide
+			{}% ne rien ins\xE9rer
+			{% sinon
+			\lower.5ex\hbox{ #2 }% ins\xE9rer le titre abaiss\xE9 de 0.5ex
+			\algohrulefill% ins\xE9rer une ligne horizontale
+			}%
+		\par% aller \xE0 la ligne
+		\nointerlineskip% ne pas ins\xE9rer le ressort d'interligne
+		\kern7pt % et sauter 7pt verticalement
+		\nobreak% emp\xEAcher une coupure de page
+		%%%%%%%%%%%%%% fin du titre %%%%%%%%%%
+		%
+		%%%%%%%%%%%%%% rend les caract\xE8res actifs %%%%%%%%%%%%%%
+		\def~##1~{\begingroup\bf##1\endgroup}%
+		\defactive:{% rend ":" actif
+			\futurelet\nxttok\algoassign% \nxttok = token suivant
+		}%
+		\def\algoassign{% suite du code de ":"
+			\ifx=\nxttok% si ":" est suivi de "="
+				\ifmmode% si mode math
+					\leftarrow% afficher "\leftarrow"
+				\else% si mode texte
+					${}\leftarrow{}$% passer en mode math pour "\leftarrow"
+				\fi
+				\expandafter\gobone% manger le signe "="
+			\else% si ":" n'est pas suivi de "="'
+				\string:% afficher ":"
+			\fi
+		}%
+		\ifnumalgo% si la num\xE9rotation est demand\xE9e,
+			\everypar={% d\xE9finir le \everypar
+				\llap{$\scriptstyle\number\algocnt$\kern\dimexpr4pt+\leftskip\relax}%
+			}%
+		\fi
+		\doforeach\currentchar\in{#1}{\catcode\expandafter`\currentchar=12 }%
+		\def\algocr{% d\xE9finit ce que fait ^^M
+			\color{black}% repasse en couleur noire
+			\rm% fonte droite
+			\leavevmode\par% termine le paragraphe
+			\advance\algocnt by1 % incr\xE9mente le compteur de lignes
+			\leftskip=0pt % initialise le ressort gauche
+		}
+		\letactive\^^M=\algocr%
+		\defactive\^^I{\advance\leftskip by \algoindent\relax}%
+		\defactive\ {\hskip1.25\fontdimen2\font\relax}% espace = 25% de + que
+		                                              % la largeur naturelle
+		\defactive\%{\it\color{gray}\char`\%}% passe en italique et gris puis affiche "%"
+		\defactive_{\ifmmode_\else\string_\fi}%
+		\defactive#3{% rend le token #3 actif (il sera rencontr\xE9 \xE0 la fin de l'algorithme)
+			\everypar{}% neutralise le \everypar
+			\par% aller \xE0 la ligne
+			\nointerlineskip% ne pas ins\xE9rer le ressort d'interligne
+			\kern7pt % et sauter 7pt verticalement
+			\nobreak% emp\xEAcher une coupure de page
+			\algohrulefill% tracer la ligne de fin
+	\endgroup% ferme le groupe ouvert au d\xE9but de l'algorithme
+	\smallbreak% saute un petit espace vertical
+		}%
+	%%%%%%%%%%%%%%%%% fin des caract\xE8res actifs %%%%%%%%%%%%%%%%
+	\sanitizealgo% va manger les espaces et les ^^M au d\xE9but de l'algo
+}
+
+\def\sanitizealgo{\futurelet\nxttok\checkfirsttok}% r\xE9cup\xE8re le prochain token
+
+\def\checkfirsttok{% teste le prochaun token
+	\def\nextaction{% a priori, on consid\xE8re que la suite est " " ou "^^M" donc
+		\afterassignment\sanitizealgo% aller \xE0 \sanitizealgo
+		\let\nexttok= % apr\xE8s avoir mang\xE9 ce "^^M" ou cet espace
+	}%
+	\unless\ifx\nxttok\algocr% si le prochain token n'est pas un ^^M
+		\unless\ifx\space\nxttok% et si le prochain token n'est pas un espace
+			\let\nextaction\relax% ne rien faire ensuite
+		\fi
+	\fi
+	\nextaction% faire l'action d\xE9cid\xE9e ci-dessus
+}
+
+Voici un algorithme \xE9l\xE9mentaire
+\algorithm[\#]{Algorithme {\bf MinMax}}|
+macro ~Min_Max~ (#1) % afficher la valeur max et min d'une liste de valeurs #1
+W$V_{max}:=-\infty$ % $-\infty$ ou la plus petite valeur possible
+W$V_{min}:=+\infty$ % $+\infty$ ou la plus grande valeur possible
+W~Pour~ chaque $x$ dans (#1)
+WW~Si~ $x>V_{max}$
+WWW~alors~ $V_{max}:=x$
+WW~FinSi~
+WW~Si~ $x<V_{min}$
+WWW~alors~ $V_{min}:=x$
+WW~FinSi~
+W~FinPour~
+WAfficher "$V_{min}$ et $V_{max}$"
+~FinMin_Max~|
+Suite du texte...
+****************** Fin code ******************
+
+
+****************** Code 437 ******************
+a) \meaning a\par
+b) \meaning {\par
+c) \meaning _\par
+d) \meaning\def\par % une primitive
+e) \meaning\baselineskip\par% une primitive
+f) \long\def\foo#1#2.#3{#1 puis #2 et #3 !}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 438 ******************
+\def\foo#1#2{%
+	\def\argA{#1}\show\argA% d\xE9bogage
+	Bonjour #1 et #2}
+\foo{{\bf X}}{Y}
+****************** Fin code ******************
+
+
+****************** Code 439 ******************
+\def\foo#1#2{%
+	\showtokens{#1}% d\xE9bogage
+	Bonjour #1 et #2}
+\foo{{\bf X}}{Y}
+****************** Fin code ******************
+
+
+****************** Code 440 ******************
+\newtoks\footoks
+\footoks={foo bar}
+\show\footoks
+****************** Fin code ******************
+
+
+****************** Code 441 ******************
+\showthe\baselineskip% registre-primitive
+\newtoks\footoks \footoks={foo bar} \showthe\footoks
+\newcount\foocount \foocount=987 \showthe\foocount
+\newdimen\foodimen \foodimen=3.14pt \showthe\foodimen
+\newskip\fooskip \fooskip=10 pt plus 1pt minus 1fil \showthe\fooskip
+\newbox\foobox \foobox\hbox{foo} \showthe\foobox
+****************** Fin code ******************
+
+
+****************** Code 442 ******************
+\def\foo#1,#2\endfoo{Bonjour #1 et #2}
+\tracingmacros=1
+\foo moi,toi\endfoo
+\tracingmacros=0
+****************** Fin code ******************
+
+
+****************** Code 443 ******************
+\tracingcommands=2
+Foo \hbox{et \ifnum2>1 bar\else toi\fi}\par
+Suite
+\tracingcommands=0
+****************** Fin code ******************
+
+
+****************** Code 444 ******************
+\def\i{\advance\count255 1 }
+\tracingrestores=1
+\count255=2 {\i\i\i}
+\tracingrestores=0
+****************** Fin code ******************
+
+
+****************** Code 445 ******************
+\def\i{\advance\count255 1 } \def\gi{\global\i}
+\tracingrestores=1
+\count255=2 {\i\i\gi\i\gi\i}
+\tracingrestores=0
+****************** Fin code ******************
+
+
+****************** Code 446 ******************
+\catcode`@11
+\def\ifnodecpart#1{\ifnodecpart at i#1.\@nil}
+\def\ifnodecpart at i#1.#2\@nil{\ifempty{#2}}
+\def\decadd#1#2{% #1 et #2=nombre \xE0 additionner
+	\ifnodecpart{#1}% si #1 est un entier
+		{\ifnodecpart{#2}% et #2 aussi, les additionner avec \numexpr
+			{\number\numexpr#1+#2\relax}%
+			{\decadd at i#1.0\@nil#2\@nil}% sinon, ajouter ".0" apr\xE8s #1
+		}
+		{\ifnodecpart{#2}% si #1 a une partie enti\xE8re mais pas #2
+			{\decadd at i#1\@nil#2.0\@nil}% ajouter ".0" \xE0 #2
+			{\decadd at i#1\@nil#2\@nil}% sinon, les 2 parties enti\xE8res sont pr\xE9sentes
+		}%
+}
+\def\decadd at i#1.#2\@nil#3.#4\@nil{% affiche les parties enti\xE8res et d\xE9cimales re\xE7ues
+	$x_a=#1\quad y_a=#2\qquad x_b=#3\quad y_b=#4$
+}
+\catcode`@12
+a) \decadd{5}{9.4}\par
+b) \decadd{-3.198}{-6.02}\par
+c) \decadd{0.123}{123}
+****************** Fin code ******************
+
+
+****************** Code 447 ******************
+\def\addzeros#1#2/#3.#4#5/#6.#7/{%
+	Arguments re\xE7us : #1#2/#3.#4#5/#6.#7/\par% afficher ce que la macro re\xE7oit
+	\ifempty{#2}% si #1 est le dernier chiffre de y
+		{\ifempty{#5}% et si #4 est le dernier chiffre de y2
+			{R\xE9sultat final : \detokenize{{#3#1}{#6#4}{#70}}}% afficher le r\xE9sultat final
+			{\addzeros0/#3#1.#5/#6#4.#70/}% sinon alimenter #1 avec un 0
+		}
+		{\ifempty{#5}% si #4 est le dernier chiffre de y2
+			{\addzeros#2/#3#1.0/#6#4.#70/}% alimenter #4 avec un 0
+			{\addzeros#2/#3#1.#5/#6#4.#70/}% #2 et #5 non vides
+		}%
+}
+\addzeros457/.689714/.1/
+****************** Fin code ******************
+
+
+****************** Code 448 ******************
+\catcode`\@11
+\def\addzeros#1#2/#3.#4#5/#6.#7/{%
+	\ifempty{#2}% si #1 est le dernier chiffre de y1
+		{\ifempty{#5}% et si #4 est le dernier chiffre de y2
+			{{#3#1}{#6#4}{#70}}% redonner les 3 arguments
+			{\addzeros0/#3#1.#5/#6#4.#70/}% sinon alimenter #1 avec un 0
+		}
+		{\ifempty{#5}% si #4 est le dernier chiffre de y2
+			{\addzeros#2/#3#1.0/#6#4.#70/}% alimenter #4 avec un 0
+			{\addzeros#2/#3#1.#5/#6#4.#70/}% #2 et #5 non vides
+		}%
+}
+\def\decadd#1#2{% #1 et #2=nombre \xE0 additionner
+	\ifnodecpart{#1}
+		{\ifnodecpart{#2}{\number\numexpr#1+#2\relax}{\decadd at i#1.0\@nil#2\@nil}}
+		{\ifnodecpart{#2}{\decadd at i#1\@nil#2.0\@nil}{\decadd at i#1\@nil#2\@nil}}%
+}
+\def\decadd at i#1.#2\@nil#3.#4\@nil{%
+	\expandafter\decadd at ii
+			\romannumeral-`\0\addzeros#2/.#4/.1/% se d\xE9veloppe en 3 arguments
+			{#1}
+			{#3}%
+}
+\def\decadd at ii#1#2#3#4#5{%
+% #1 et #2=parties d\xE9cimales (m\xEAmes longueurs);
+% #3=seuil de retenue; #4 et #5=parties enti\xE8res
+	\exptwoargs{\decadd at iii{#3}}% envoyer le seuil de retenue tel quel
+		% sommer les parties d\xE9cimales sign\xE9es
+		{\number\numexpr\true at sgn{#4}#1+\true at sgn{#5}#2\relax}%
+		% et les parties enti\xE8res
+		{\number\numexpr#4+#5\relax}%
+}
+\def\decadd at iii#1#2#3{%
+	seuil de retenue = #1 \qquad nombre = "#3"."#2"%
+}
+\catcode`\@12
+a) \decadd{6.7}{3.498}\par
+b) \decadd{1.67}{-4.9}\par
+c) \decadd{3.95}{2.0005}\par
+d) \decadd{1.007}{2.008}\par
+e) \decadd{-7.123}{3.523}
+****************** Fin code ******************
+
+
+****************** Code 449 ******************
+\catcode`\@11
+\def\format at dec#1#2{% #1=partie d\xE9cimale #2=seuil de retenue
+	\expandafter\gobone% le \gobone agira en dernier,
+		\romannumeral-`\0% mais avant, tout d\xE9velopper
+		\expandafter\reverse\expandafter% et retarder le \reverse de fin
+			% pour d\xE9velopper son argument qui
+			{\number% d\xE9veloppe tout et \xE9value avec \number
+				\expandafter\reverse\expandafter% l'inversion de
+				{\number\numexpr\abs{#1}+#2\relax}% |#1|+#2
+			}%
+}
+a) \format at dec{710}{100000}\par
+b) \format at dec{6}{100}\par
+c) \format at dec{-12300}{1000000}
+\catcode`\@12
+****************** Fin code ******************
+
+
+****************** Code 450 ******************
+\catcode`@11
+\def\true at sgn#1{\ifnum#11<\z at -\fi}
+\def\decadd#1#2{% #1 et #2=nombre \xE0 additionner
+ 	\romannumeral-`\.% tout d\xE9velopper jusqu'\xE0 l'affichage du nombre (\decadd at iv)
+	\ifnodecpart{#1}% si #1 est un entier
+		{\ifnodecpart{#2}% et #2 aussi, les additionner avec \numexpr
+			{\numexpr#1+#2\relax}%
+			{\decadd at i#1.0\@nil#2\@nil}% sinon, ajouter ".0" apr\xE8s #1
+		}
+		{\ifnodecpart{#2}% si #1 a une partie enti\xE8re mais pas #2
+			{\decadd at i#1\@nil#2.0\@nil}% ajouter ".0" \xE0 #2
+			{\decadd at i#1\@nil#2\@nil}% sinon, les 2 parties enti\xE8res sont pr\xE9sentes
+		}%
+}
+\def\decadd at i#1.#2\@nil#3.#4\@nil{%
+	\expandafter\decadd at ii
+			\romannumeral-`\0\addzeros#2/.#4/.10/% se d\xE9veloppe en 3 arguments
+			{#1}
+			{#3}%
+}
+\def\decadd at ii#1#2#3#4#5{%
+% #1 et #2=parties d\xE9cimales (m\xEAmes longueurs)
+% #3=seuil de retenue; #4 et #5=parties enti\xE8res
+	\exptwoargs{\decadd at iii{#3}}% envoyer le seuil de retenue tel quel
+		% sommer les parties d\xE9cimales sign\xE9es
+		{\number\numexpr\true at sgn{#4}#1+\true at sgn{#5}#2\relax}%
+		% et les parties enti\xE8res
+		{\number\numexpr#4+#5\relax}%
+}
+\def\decadd at iii#1#2#3{% #1=seuil de retenue #2=partie d\xE9cimale #3= partie enti\xE8re
+	\ifnum\true at sgn{#2}\true at sgn{\ifnum#3=\z@#2\else#3\fi}1=-1 % si les signes sont
+	                                                           % diff\xE9rents
+	\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+		{\exptwoargs\decadd at iv% transmettre les arguments modifi\xE9s :
+			{\number\numexpr#3-\true at sgn{#3}1}% #3:=#3-sgn(#3)1
+			{\number\numexpr#2-\true at sgn{#2}#1}% #2:=#2-sgn(#2)10^n
+			{#1}%
+		}% si les signes sont \xE9gaux
+		{\ifnum\abs{#2}<#1 % et si abs(y)<10^n
+		\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+			{\decadd at iv{#3}{#2}{#1}% tranmettre les arguments tels quels
+			}
+			{\exptwoargs\decadd at iv% sinon
+				{\number\numexpr#3+\true at sgn{#3}1}% #3:=#3+sgn(#3)1
+				{\number\numexpr#2-\true at sgn{#2}#1}% #2:=#2-sgn(#2)10^n
+				{#1}%
+			}%
+		}%
+}
+\def\decadd at iv#1#2#3{% affiche le d\xE9cimal "#1.#2"
+	% le d\xE9veloppement maximal initi\xE9 par le \romannumeral de \decadd est actif
+	\ifnum#1=\z@\ifnum#2<\z@% si #1=0 et #2<0
+		\expandafter\expandafter\expandafter% transmettre le d\xE9veloppement \xE0 \number
+		-% puis afficher le signe "-"
+	\fi\fi
+	\number#1% affiche #1 qui est la somme des parties enti\xE8res
+	% poursuivre le d\xE9veloppement initi\xE9 par \number
+	\unless\ifnum#2=\z@% si la partie d\xE9cimale est diff\xE9rente de 0
+		\antefi% se d\xE9barrasser de \fi
+		\expandafter.% afficher le "." d\xE9cimal apr\xE8s avoir
+		\romannumeral-`\0\format at dec{#2}{#3}% correctement g\xE9r\xE9 les 0 de #2
+	\fi
+}
+\def\addzeros#1#2/#3.#4#5/#6.#7/{%
+	\ifempty{#2}% si #1 est le dernier chiffre de y1
+		{\ifempty{#5}% et si #4 est le dernier chiffre de y2
+			{{#3#1}{#6#4}{#7}}% redonner les 3 arguments
+			{\addzeros0/#3#1.#5/#6#4.#70/}% sinon alimenter #1 avec un 0
+		}
+		{\ifempty{#5}% si #4 est le dernier chiffre de y2
+			{\addzeros#2/#3#1.0/#6#4.#70/}% alimenter #4 avec un 0
+			{\addzeros#2/#3#1.#5/#6#4.#70/}% #2 et #5 non vides
+		}%
+}
+\def\format at dec#1#2{% #1=partie d\xE9cimale #2=seuil de retenue
+	\expandafter\gobone% le \gobone agira en dernier,
+		\romannumeral-`\0% mais avant, tout d\xE9velopper
+		\expandafter\reverse\expandafter% et retarder le \reverse de fin
+			% pour d\xE9velopper son argument qui
+			{\number% d\xE9veloppe tout et \xE9value avec \number
+				\expandafter\reverse\expandafter% l'inversion de
+				{\number\numexpr\abs{#1}+#2\relax}% abs(#1)+#2
+			}%
+}
+\catcode`@12
+a) $-3.78+1.6987=\decadd{-3.78}{1.6987}$\par
+b) $3.56-3.06=\decadd{3.56}{-3.06}$\par
+c) $4.125+13.49=\decadd{4.125}{13.49}$\par
+d) $-0.99+1.005=\decadd{-0.99}{1.005}$\par
+e) $16.6-19.879=\decadd{16.6}{-19.879}$\par
+f) $5.789-0.698=\decadd{5.789}{-0.698}$\par
+g) $0.123-0.123=\decadd{0.123}{-0.123}$\par
+h) $3.14-16.4912=\decadd{3.14}{-16.4912}$\par
+i) $0.1-0.98=\decadd{0.1}{-0.98}$\par
+j) $2.43+7.57=\decadd{2.43}{7.57}$\par
+h) \edef\foo{\decadd{1.23}{9.78}}\meaning\foo\par
+j) \detokenize\expandafter\expandafter\expandafter{\decadd{3.14}{-8.544}}
+****************** Fin code ******************
+
+
+****************** Code 451 ******************
+a) \pdfstrcmp{foo}{bar}\qquad
+b) \pdfstrcmp{bar}{foo}\qquad
+c) \def\foo{ABC}\pdfstrcmp{\foo}{ABC}\qquad
+d) \edef\foo{\string_}\pdfstrcmp{1_2}{1\foo2}\qquad
+e) \pdfstrcmp{\string\relax}{\relax}
+****************** Fin code ******************
+
+
+****************** Code 452 ******************
+\edef\tempcompil{\number\pdfelapsedtime}%
+Depuis le d\xE9but de la compilation, il s'est \xE9coul\xE9 \tempcompil{} secondes d'\xE9chelle,
+soit \convertunit{\tempcompil sp}{pt} secondes.
+****************** Fin code ******************
+
+
+****************** Code 453 ******************
+%%%%%%%%%% definition de \loop...\repeat comme plain-TeX %%%%%%%%%%
+\def\loop#1\repeat{\def\body{#1}\iterate}
+\def\iterate{\body \let\next\iterate \else\let\next\relax\fi \next}
+\let\repeat=\fi
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\newcount\testcnt
+\pdfresettimer% remet le compteur \xE0 0
+	\testcnt=0
+	\loop % Test no 1
+		\ifnum\testcnt<100000 \advance\testcnt 1 
+	\repeat
+Temps 1 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle loop de \TeX)\par
+%%%%%%%%%%%% definition de \loop...\repeat comme LaTeX %%%%%%%%%%%%
+\def\loop#1\repeat{\def\iterate{#1\relax\expandafter\iterate\fi}%
+  \iterate \let\iterate\relax}
+\let\repeat\fi
+\pdfresettimer% remet le compteur \xE0 0
+	\testcnt=0
+	\loop % Test no 2
+		\ifnum\testcnt<100000
+		\advance\testcnt 1 
+	\repeat
+Temps 2 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle loop de \LaTeX)\par
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\pdfresettimer% remet le compteur \xE0 0
+	\for\ii=1 to 100000\do{}% Test no 3
+Temps 3 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle for)
+****************** Fin code ******************
+
+
+****************** Code 454 ******************
+%%%%%%%%%%%% definition de \loop...\repeat comme LaTeX %%%%%%%%%%%%
+\def\loop#1\repeat{\def\iterate{#1\relax\expandafter\iterate\fi}%
+  \iterate \let\iterate\relax}
+\let\repeat\fi
+\pdfresettimer% remet le compteur \xE0 0
+	\def\ii{0}%
+	\loop % Test no 1
+		\ifnum\ii<100000
+		\edef\ii{\number\numexpr\ii+1\relax}%
+	\repeat
+Temps 1 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle loop de \LaTeX)\par
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\pdfresettimer% remet le compteur \xE0 0
+	\for\ii=1 to 100000\do{}% Test no 2
+Temps 2 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle for)
+****************** Fin code ******************
+
+
+****************** Code 455 ******************
+\newcount\testcnt
+\pdfresettimer
+\testcnt=0
+\for\ii=1 to 100000\do{\advance\testcnt1 }
+Temps 1 : \convertunit{\pdfelapsedtime sp}{pt} s (incr\xE9mentation compteur)
+
+\pdfresettimer
+\def\foo{0}%
+\for\ii=1 to 100000\do{\edef\foo{\number\numexpr\foo+1\relax}}%
+Temps 2 : \convertunit{\pdfelapsedtime sp}{pt} s (incr\xE9mentation du texte de remplacement)
+****************** Fin code ******************


Property changes on: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/apprendre-a-programmer-en-tex.tex
===================================================================
--- trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/apprendre-a-programmer-en-tex.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/apprendre-a-programmer-en-tex.tex	2019-05-02 22:34:52 UTC (rev 50933)
@@ -0,0 +1,19358 @@
+% !TeX spellcheck = fr_FR
+% !TeX encoding = ISO-8859-1
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%                                                                          %%
+%%                           Code source du livre                           %%
+%%                     \xAB Apprendre \xE0 programmer en TeX \xBB                    %%
+%%                                                                          %%
+%%                                   ___                                    %%
+%%                                                                          %%
+%%                        \xA9 2014 Christian Tellechea                        %%
+%%                                                                          %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% ___________________________________________________________________________
+%|                                                                           |
+%|                    Encodage ISO 8859-1 (latin1)                           |
+%|               \xC0 compiler avec pdflatex en mode pdf                        |
+%|___________________________________________________________________________|
+
+\RequirePackage{etex}
+\documentclass[fontsize=10pt,chapterprefix=true]{scrbook}
+
+\newwrite\wtest
+\newread\rtest
+
+\usepackage[latin1]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage[
+	paperwidth=16.8275cm,paperheight=26.035cm,
+	headsep=.5cm,headheight=1cm,
+	footskip=1cm,
+	twoside,
+	lmargin=2.2cm,
+	rmargin=2.8775cm,
+	tmargin=2.5cm,
+	bmargin=3cm
+	]{geometry}% largeur texte = 16.8275-(2.8775+2.2)=11,75 cm
+
+\usepackage[table]{xcolor}
+\definecolor{shadecolor}{rgb}{0.86078,0.86078,0.86078}% couleur de fond des environnements "regle"
+
+\usepackage{
+	metalogo,
+	tikz,
+	xspace,
+	dashbox,
+	fancybox,
+	enumitem,
+	longtable,
+	framed,
+	graphicx,
+	amsmath,
+	needspace
+}
+\xspaceaddexceptions{\footnote\verb)}
+\usetikzlibrary{decorations}
+\usepgflibrary{decorations.pathmorphing}
+% ____________________________________________________________________________
+%|                                                                            |
+%|                     Macros d\xE9finies dans le livre                          |
+%|                                                                            |
+\input progtexmacro.tex%                                                      |
+%|                                                                            |
+%|____________________________________________________________________________|
+
+\makeatletter
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                         environnements "liste"                             |
+%|                                                                            |
+\newlist{algo}{enumerate}{4}
+\setlist[algo]{leftmargin=*,labelindent=\main at parindent,itemsep=0pt,topsep=4pt,parsep=1.5pt,before=\small}
+\setlist[algo,1]{label=\arabic*),topsep=2pt,ref=\arabic*}
+\setlist[algo,2]{label=\alph*),topsep=1pt,ref=\thealgoi.\alph*}
+\setlist[algo,3]{label=\roman*),topsep=1pt,ref=\thealgoii.\roman*}
+\setlist[algo,4]{label=--,topsep=1pt,ref=\thealgoiii.\roman*}
+
+\setlist[enumerate]{leftmargin=*,labelindent=\main at parindent,itemsep=0.3pt,topsep=1pt,parsep=1pt,partopsep=0pt}
+
+\setlist[itemize]{leftmargin=*,labelindent=\main at parindent,itemsep=0.3pt,topsep=1pt,parsep=1pt,partopsep=0pt,label=--}
+%|                                                                            |
+%|                        fin environnements "liste"                          |
+%|____________________________________________________________________________|
+
+\usepackage[bottom]{footmisc}
+
+\usepackage{scrlayer-scrpage}
+\pagestyle{scrheadings}
+\clearscrheadfoot
+\cehead{\leftmark}
+\cohead{\rightmark}
+\lehead{\llap{\normalfont\bfseries\thepage\kern4mm }}
+\rohead{\rlap{\normalfont\bfseries\kern4mm \thepage}}
+\automark[chapter]{part}
+\renewcommand\partmarkformat{\ifnum\arabic{part}>0 \normalfont\biolinum\small\itshape\thepart. \fi}
+\renewcommand\chaptermarkformat{\normalfont\biolinum\small\itshape\thechapter. }
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                              Polices                                       |
+%|                                                                            |
+\usepackage{amssymb,textcomp,eurosym,libertine}
+\usepackage[libertine]{newtxmath}
+\renewcommand*\ttdefault{LinuxLibertineMonoTC-TLF}
+\DeclareRobustCommand*\libLegacyGlyph[1]{{\ifcsname fxl@#1\endcsname\@nameuse{fxl@#1}\else\errmessage{glyphe fxl@#1 non d\xE9fini}\fi}}
+\DeclareRobustCommand*\bioLegacyKeyGlyph[1]{{\ifcsname fxk@#1\endcsname\@nameuse{fxk@#1}\else\errmessage{glyphe fxk@#1 non d\xE9fini}\fi}}
+\newcommand*\DeclareTextGlyphX[5]{\@namedef{#1@#4}{{\fontfamily{#3}\fontencoding{#2}\selectfont\char#5\relax}}}
+\DeclareTextGlyphX{fxk}{U}{fxke1}{T_a_b}{117}
+\DeclareTextGlyphX{fxk}{U}{fxke1}{E_n_t_e_r}{118}
+\DeclareTextGlyphX{fxk}{U}{fxke1}{A_l_t_G_r}{114}
+\DeclareTextGlyphX{fxk}{U}{fxk00}{A}{65}
+\DeclareTextGlyphX{fxk}{U}{fxk00}{R}{82}
+\DeclareTextGlyphX{fxk}{U}{fxk00}{seven}{55}
+\DeclareTextGlyphX{fxl}{U}{fxle0}{Q_u}{72}
+\DeclareTextGlyphX{fxl}{U}{fxle0}{uniE007}{7}
+\newcommand*\Qu{\libLegacyGlyph{Q_u}}% <- pour \xE9viter de cr\xE9er une fonte virtuelle
+%|                                                                            |
+%|                            fin Polices                                     |
+%|____________________________________________________________________________|
+
+\usepackage{lettrine}
+\usepackage[
+	protrusion=true,
+	expansion=true,
+	stretch=10,
+	shrink=5,
+	tracking=true,
+	final,
+	babel=true]{microtype}
+\usepackage[autolanguage]{numprint}
+% ____________________________________________________________________________
+%|                                                                            |
+%|                               Mises en forme                               |
+%|                                                                            |
+\let\lcodedelim=\langle
+\let\rcodedelim=\rangle
+\DeclareRobustCommand\codeelement[1]{% met en forme <"#1">
+	\ensuremath\lcodedelim\textit{#1}\ensuremath\rcodedelim
+}
+\let\Verb=\verb
+\def\def at visible@space{%
+	\setbox0\hbox{x}%
+	\def\visible at space{%
+		\leavevmode
+		\kern.1ex
+		\vrule width0.4pt height0.5ex depth0.2ex\relax
+		\vrule width\dimexpr\wd0-.8pt-.2ex\relax height\dimexpr.4pt-.2ex\relax depth0.2ex\relax
+		\vrule width0.4pt height0.5ex depth0.2ex\relax
+		\kern.1ex
+		}%
+}
+\def\verb{%
+	\relax\ifmmode\hbox\else\leavevmode\null\fi
+	\bgroup
+		\ttfamily
+		\hyphenchar\font=-1
+		\for\ii=0 to 255 \do {\catcode\ii=12 }%
+		\catcode`\~13
+		\obeylines \verbatim at font \@noligs \hyphenchar\font=-1
+		\ifstarred{\def at visible@space\letactive\ =\visible at space\catcode`\~12 \verb at i}{\letactive\ =\space\catcode`\~12\frenchspacing\verb at i}%
+}
+\def\verb at i#1{%
+		\def\verb at ii##1#1{\verb at iii{##1}}%
+		\verb at ii
+}
+\catcode`\>=13
+\catcode`\<=13
+\def\verb at element#1>{\codeelement{#1}}
+\def\verb at iii#1{%
+		\ifin{#1}<%
+			{\def\temp at l{#1}\let\temp at r\temp at l%
+			\leftofsc\temp at l<%
+			\rightofsc\temp at r<%
+			\exparg\ifin\temp at r>%
+				{\addtomacro\temp at l\verb at element
+				\eaddtomacro\temp at l\temp at r
+				\exparg\verb at iii\temp at l
+				}
+				{#1\egroup}%
+			}
+			{#1\egroup}%
+}
+\catcode`\>=12
+\catcode`\<=12
+
+\newcount\exercice at cnt
+\exercice at cnt\z@
+
+\newmacro\defactive[\def]1{%
+	\catcode`#2=13
+	\begingroup
+	\lccode`~=`#2
+	\lowercase{\endgroup#1~}}
+
+\newcounter{exemple}[part]
+
+\newenvironment{centrage}[1][3.5pt]
+	{\ifvmode\removelastskip\fi
+	\list{}{\leftmargin\z@\parsep\z@\topsep#1\relax}%
+	\centering\item\relax
+	}%
+	\endlist
+
+\newcommand\boxtoken[2][\string]{%
+	\begingroup
+		\fboxsep\boxtokensep
+		\fbox{\ttfamily\vphantom{Ailpj}#1#2}%
+	\endgroup
+	\xspace
+}
+\newcommand*\boxtokensep{0.3pt}
+
+\newcommand*\TeXhead{$\ggg$}
+\newcommand*\Hex[1]{\hbox{$\mathsf{#1}_{\scriptscriptstyle\mathsf h}$}}
+\newcommand*\bin[1]{\textit{#1}}
+\newcommand*\latin{\texttt{latin1}\xspace}
+\newcommand*\utf{\texttt{UTF8}\xspace}
+
+\newenvironment{exercice}
+	{%
+	\needspace{3.5\baselineskip}%
+	\setlist[enumerate]{leftmargin=*,labelindent=\main at parindent,itemsep=0pt,topsep=1pt,parsep=1pt}%
+	\parindent\z@
+	\parskip2pt plus.5pt minus.5pt
+	\global\advance\exercice at cnt\@ne
+	\bigbreak
+	\small\noindent
+	\rule{1.25ex}{1.25ex}\kern1ex \textsc{\textbf{Exercice \number\exercice at cnt}}\par\nobreak
+	}
+	{\ifvmode
+		\vskip\dimexpr2pt-\baselineskip-\lastskip\relax
+	\fi
+	\hfill\rule{1.25ex}{1.25ex}\bigbreak}
+
+\FrameSep=5pt
+\newcount\cnt at regle
+\newwrite\reglewrite
+\immediate\openout\reglewrite=regles.txt
+\immediate\write\reglewrite{%
+	\string\newcount\string\recapreglecnt\string^^J%
+	\string\recapreglecnt=0\relax
+	\string^^J%
+}
+\newenvironment{regle}[1][R\xE8gle]{%
+	\global\advance\cnt at regle\@ne
+	\begingroup
+		\gdef\titre at regle{#1}%
+		\for\xxx=0 to 255\do{\catcode\xxx=12 }%
+		\captureregle
+	}
+	{}
+\begingroup\edef\temp{\endgroup\def\noexpand\captureregle##1\string\end\detokenize{{regle}}}
+\temp{%
+	\endgroup
+	\newlinechar`\^^M
+	\immediate\write\reglewrite{%
+		\string\begin{recapregle}#1\string\end{recapregle}\string^^J%
+		}%
+	\begingroup
+		\parskip2pt plus.25pt minus.25pt
+		\setlist[itemize]{leftmargin=2em,itemsep=0pt,topsep=1pt,parsep=1pt,label=--}%
+		\newlinechar`\^^M
+		\everyeof{\noexpand}%
+		\makeatletter
+		\scantokens{%
+			\parindent\z@
+			\shaded
+				{\bfseries\scshape\number\cnt at regle{} - \titre at regle}%
+				\par\nobreak
+				#1%
+			\endshaded
+			}%
+	\endgroup
+	\end{regle}%
+}%
+
+\newenvironment{recapregle}%
+	{\bigbreak
+	\global\advance\recapreglecnt 1
+	\let\label=\gobone
+	\small
+	\parindent=0pt
+	\parskip1pt plus.25pt minus.25pt
+	\setlist[itemize]{leftmargin=3.5em,itemsep=0pt,topsep=1pt,parsep=1pt,label=--}%
+	\textbf{\number\recapreglecnt\relax.\kern0.33333em}%
+	}
+	{}
+
+\newcommand\solution[1][]{%
+	\needspace{3\baselineskip}%
+	\smallbreak\noindent%\incorrectiontrue
+	{\fboxsep\z@\fboxrule.5pt \fbox{\vrule height1ex width\z@\kern1ex }}%
+	\hspace{1ex}\textsc{\textbf{Solution\ifempty{#1}{}{ #1}}}\par\nobreak
+}
+
+% Centre la ligne de code en mode verbatim
+% Utilisation : \centrecode*-code-
+% "*" facultative. Si pr\xE9sent, les espaces sont rendus visibles
+% code est un code se trouvant entre 2 caract\xE8res identiques.
+% Si * : ne tient pas compte des "<" et ">"
+\def\centrecode{\def\space at def{\defactive\ {\space}}\centrecode@}
+
+\def\centrecodespc{\def\space at def{\catcode`\ =12 }\centrecode@}
+
+\def\centrecode@{%
+	\par\unskip
+	\begingroup
+		\parskip\z@
+		\catcode`\\xA4=13
+		\begingroup
+			\lccode`\~`\\xA4\relax
+			\lowercase{\endgroup\long\def~##1~}{%
+				\begingroup
+					\catcode`\{=1 \catcode`\}=2 \catcode`\#=6 \catcode`\\=0 \catcode`\$=3
+					\catcode`\f=11
+					\endlinechar=-1
+					\scantokens{##1}%
+				\endgroup
+				}% \xE9chappement de \xA4...\xA4
+		\parindent\z@\let\do\@makeother\dospecials
+		\defactive\,{\kern\z@\string,}%
+		\defactive\-{\kern\z@\string-}%
+		\defactive\^^M{\normalfont\ttfamily\color{black}\cr{}}%
+		\defactive\^^I{{ }{ }{ }{ }}% tab = 4 espaces
+		\defactive\%{\itshape\color{gray}\char`\% }%
+		\space at def
+		\@ifstar
+			{\let\centrecode at iii=\centrecode at star
+			\defactive\<{\string<{}}%
+			\defactive\>{\string>{}}%
+			\centrecode at i
+			}
+			{\let\centrecode at iii=\centrecode at nostar
+			\centrecode at i
+			}%
+}
+
+\def\centrecode at i#1{%
+	\def\centrecode at ii##1#1{\centrecode at iii{##1}}%
+	\centrecode at ii}
+
+\def\centrecode at nostar#1{% #1 est le code
+	\ifin{#1}<%
+		{\def\temp at l{#1}\let\temp at r\temp at l%
+		\leftofsc\temp at l<%
+		\rightofsc\temp at r<%
+		\exparg\ifin\temp at r>%
+			{\addtomacro\temp at l\centrecode at element
+			\eaddtomacro\temp at l\temp at r
+			\exparg\centrecode at nostar\temp at l
+			}%
+			{\centrecode at star{#1}}%
+		}%
+		{\centrecode at star{#1}}%
+}
+
+\def\centrecode at star#1{%
+	\centrage{}\leavevmode\vbox{\small\ttfamily\halign{##\hfill\cr#1\cr\crcr}}\endcentrage
+	\endgroup\ignorespaces
+}
+\def\centrecode at element#1>{\codeelement{#1}}
+
+% Utilisation : \indentcode*[dim]-code-
+% "*" facultative. Si pr\xE9sente, les lignes sont num\xE9rot\xE9es
+% [dim] est l'indentation du code par rapport au d\xE9but des lignes. 3em par d\xE9faut
+% code se trouve entre 2 caract\xE8res identiques et peut comporter des retours \xE0 la ligne
+\newif\ifindencodenum
+\indencodenumfalse
+\newcount\indentcode at cnt
+\newcommand*\indentcode{%
+	\begingroup
+	\indentcode at cnt=\z@
+	\let\do\@makeother\dospecials
+	\catcode`\?12 \catcode`\!12
+	\@ifstar
+		\indentcode at i
+		{\defactive\ { }%
+		 \indentcode at i
+		 }%
+}
+
+\newcommand*\indentcodeactivechars[1]{%
+	\defactive\^^M{\par\hspace{#1}}%
+	\defactive\^^I{{ }{ }{ }{ }}% tab = 4 espaces
+	\catcode`\\xA4=13
+	\begingroup
+		\lccode`\~`\\xA4\relax
+		\lowercase{\endgroup\long\def~##1~}{%
+			\begingroup
+				\catcode`\{=1 \catcode`\}=2 \catcode`\#=6 \catcode`\\=0 \catcode`\$=3
+				\catcode`\f=11
+				\endlinechar=-1
+				\scantokens{##1}%
+			\endgroup
+			}% \xE9chappement \xA4...\xA4
+}
+
+\newcommand*\indentcode at i[1][\main at parindent]{%
+	\parindent\z@
+	\parskip\z@
+	\ttfamily\small
+	\ifindencodenum
+		\everypar{\advance\indentcode at cnt\@ne\llap{\footnotesize$\scriptstyle\number\indentcode at cnt$\space}}%
+	\fi
+	\par\smallskip\nobreak\noindent\hspace{#1}%
+	\indentcodeactivechars{#1}%
+	\indentcode at ii
+}
+
+\def\indentcode at ii#1{%
+	\expandafter\defactive\csname#1\endcsname{\smallbreak\endgroup\ignorespaces}%
+}
+
+\newcommand*\boxcs[2]{%
+	{\boxput*(0,1){\fboxsep\z@\colorbox{white}{\leavevmode\kern1pt\footnotesize\string#1\kern1pt}}{\fboxsep=7pt\fbox{#2}}}%
+}
+
+\newcount\node at cnt
+\newcommand*\jumptok[2][\expandatfer]{%
+	\begin{tikzpicture}[baseline,inner sep=1pt,outer sep=0pt]
+		\def\exp at tok{\ttfamily\string#1}%
+		\def\end at tok{#2}%
+		\small
+		\makeatletter
+		\@makeother\{\@makeother\}\@makeother\#%
+		\node at cnt\z@
+		\def\previous at node{n at 0}%
+		\node[anchor=base,fill=black!25](n at 0){\strut\exp at tok};
+		\jump at tok
+}
+
+\def\jump at tok#1#2#3{%
+	\advance\node at cnt\@ne
+	\node[anchor=base west,at=(\previous at node.base east)](jumped at tok){\ttfamily\strut\string#1};
+	\if\end at tok\noexpand#3%
+		\node[draw,anchor=base west,at=(jumped at tok.base east)](n@\number\node at cnt){\ttfamily\strut\string#2};
+		\draw[-stealth,shorten >=2pt](\previous at node) to[out=30,in=150] (n@\number\node at cnt);
+		\end{tikzpicture}%
+		\expandafter\@gobbletwo
+	\else
+		\node[fill=black!25,anchor=base west,at=(jumped at tok.base east)](n@\number\node at cnt){\strut\exp at tok};
+		\draw[-stealth,shorten >=2pt](\previous at node) to[out=30,in=150] (n@\number\node at cnt);
+		\edef\previous at node{n@\number\node at cnt}%
+		\expandafter\jump at tok
+	\fi{#2}{#3}%
+}
+
+\def\showcodes#1{%
+	\hbox{%
+		\texttt{\string#1}%
+		(\number`#1\relax\thinspace\string;\thinspace\number\catcode`#1\relax)%
+	}%
+	\xspace
+}
+
+\newbox\testbox
+\newif\ifshow at dimen
+\newcommand*\dimenbox{\@ifstar{\show at dimenfalse\dimenbox at i}{\show at dimentrue\dimenbox at i}}
+\newcommand*\dimenbox at i[2][100pt]{%
+	\setbox\testbox\hbox{\fontsize{#1}{#1}\selectfont #2}%
+	\begin{tikzpicture}[inner sep=0pt,outer sep=0pt,minimum size=0pt,baseline,line width=0.2pt]
+		\node[anchor=base west,draw,inner sep=-0.1pt]at(0,0)(boite){\fontsize{#1}{#1}\selectfont#2};
+		\ifshow at dimen
+			\draw[gray,overlay]([xshift=-.8cm]boite.base west)--([xshift=.5cm]boite.base east)node[pos=0,anchor=south west,black,outer sep=1pt]{\tiny ligne de}node[pos=0,anchor=north west,black,outer sep=1pt]{\tiny base};
+			\ifdim\dp\testbox>5pt
+				\draw[stealth-stealth,overlay]([xshift=.4cm]boite.base east)--([xshift=.4cm]boite.south east)node[pos=0.5,anchor=west,outer sep=3pt]{\ttfamily\scriptsize\string\dp=\the\dp\testbox};
+			\else
+				\path([xshift=.4cm]boite.base east)--([xshift=.4cm]boite.south east)node[pos=0.5,anchor=west,outer sep=3pt]{\ttfamily\scriptsize\string\dp=\the\dp\testbox};
+			\fi
+			\draw[stealth-stealth,overlay]([xshift=.4cm]boite.base east)--([xshift=.4cm]boite.north east)node[pos=0.5,anchor=west,outer sep=3pt]{\ttfamily\scriptsize\string\ht=\the\ht\testbox};
+			\draw[stealth-stealth]([yshift=.2cm]boite.north west)--([yshift=.2cm]boite.north east)node[pos=0.5,anchor=south,outer sep=3pt]{\ttfamily\scriptsize\string\wd=\the\wd\testbox};
+		\fi
+		\draw[fill,black,overlay](boite.base west)circle(1pt);%
+	\end{tikzpicture}%
+}
+%|                                                                            |
+%|                             fin mises en forme                             |
+%|____________________________________________________________________________|
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                             Commande \showcode                             |
+%|                                                                            |
+\newbox\strut at box
+\newif\if at codeline
+\newif\if at errcode
+\newif\if at comment
+\newcount\code at line
+\newcount\code at count
+\newwrite\codewrite
+\immediate\openout\codewrite=progtexcode.txt
+\exactwrite\codewrite|%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%                                                                          %%
+%%                        Codes donn\xE9s dans le livre                        %%
+%%                    \xAB Apprendre \xE0 programmer en TeX \xBB                     %%
+%%                                                                          %%
+%%                           Encodage ISO 8859-1                            %%
+%%                                   _____                                  %%
+%%                                                                          %%
+%%                        \xA9 2014 Christian Tellechea                        %%
+%%                                                                          %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Les codes et les macros comment\xE9s donn\xE9s dans ce fichier sont diffus\xE9s sous
+% la licence LaTeX project public license (LPPL) 1.2
+%
+% https://www.latex-project.org/lppl/lppl-1-2/
+% https://www.latex-project.org/lppl/lppl-1-2.txt
+%
+% Attention : ce fichier n'a pas vocation \xE0 \xEAtre compil\xE9
+\endinput|
+\let\shownumline\@codelinetrue
+\let\hidenumline\@codelinefalse
+\shownumline
+\newcommand\encadre[2]{%0 = encadre 1=d\xE9but 2=milieu 3=fin
+	\leavevmode
+	\frboxrule=0.4pt \frboxsep=3pt
+	\setbox\z@\hbox{\kern\frboxsep#2\kern\frboxsep}%
+	\hbox{%
+		\vrule width\frboxrule
+		\vtop{%
+			\vbox{%
+				\ifnum#1<2
+					\hbox to\wd\z@{%
+						\bfseries\footnotesize
+						\hrulefill
+						\kern.5em
+						\setbox\z@\hbox{Code \ifnum\arabic{part}>\z@\no\thepart-\fi\number\code at count}%
+						\ht\z@\z@ \dp\z@\z@
+						\lower.5ex\box\z@
+						\kern.5em
+						\hrulefill
+						}%
+				\fi% r\xE9glure sup\xE9rieure
+				\kern\frboxsep% espace haut
+				\box\z@
+				}%
+			\kern\dimexpr\frboxsep+.5ex\relax% espace bas
+			\ifnum#1=0 \hrule height\frboxrule\fi% r\xE9glure inf\xE9rieure
+			\ifnum#1=3 \hrule height\frboxrule\fi
+		}% r\xE9glure inf\xE9rieure
+		\vrule width\frboxrule
+	}%
+}
+
+\newcommand*\showcode{\@errcodefalse\showcode at i}
+
+\newcommand*\errcode{\@errcodetrue\showcode at i}
+
+\def\showcodeactivechars{}
+
+\newcommand*\showcode at i[1][]{%
+	\needspace{3.5\baselineskip}%
+	\global\advance\code at count1
+	\edef\saved at state{%
+		\tolerance=\the\tolerance\relax
+		\emergencystretch=\the\emergencystretch\relax
+		\hfuzz=\the\hfuzz
+		\vfuzz=\the\vfuzz
+		}%
+	\medbreak
+	\begingroup
+		\parindent\z@
+		\parskip\z@
+		\code at line\z@
+		\def\aux at code{#1}%
+		\begingroup
+			\for\xx=0 to 255 \do{\catcode\xx=12 }%
+			\showcode at ii
+}
+
+\def\assign at execcode#1\@nil{\xdef\execcode at code{#1}}
+
+\newcommand*\showcode at ii[1]{%
+			\def\showcode at iii##1#1{% ##1 est le code o\xF9 tous les catcodes sont de 12
+					\catcode`\\xA4=13
+					\begingroup
+						\lccode`\~=`\\xA4
+					\lowercase{\endgroup\def~####1~}{}%
+					\newlinechar`\^^M
+					\everyeof{\@nil}%
+					\expandafter\assign at execcode\scantokens{##1}%
+					\immediate\write\codewrite{^^J^^J%
+						****************** Code \number\code at count \space******************^^J%
+						\execcode at code
+						****************** Fin code ******************}%
+		\endgroup
+		\def\showcode at code{##1}%
+		\afterassignment\showcode at iv
+		\if at errcode\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
+			{\def\err at message}
+			{\let\err at message\@empty}%
+		}%
+		\showcode at iii
+}
+\definecolor{codegray}{gray}{0.375}% gris pour les commentaires dans \showcode
+\newcommand*\showcode at iv{%
+		\def\FrameCommand{\encadre0}%
+		\def\FirstFrameCommand{\encadre1}%
+		\def\MidFrameCommand{\encadre2}%
+		\def\LastFrameCommand{\encadre3}%
+		\topsep1.5ex %espace avant l'encadrement
+		\par\nointerlineskip\nobreak
+		\edef\restorevbadness{\vbadness=\the\vbadness\relax}%
+		\vbadness=10000
+		\MakeFramed{\advance\hsize-\width\FrameRestore}%
+			\begingroup
+				\footnotesize
+				\everyeof{\noexpand}%
+				\begingroup
+					\if at codeline\everypar{\num at code}\fi
+					\gray at line
+					\let\do\@makeother\dospecials
+					\catcode`\\xA4=13
+					\begingroup
+						\lccode`\~`\\xA4\relax
+						\lowercase{\endgroup\long\def~##1~}{%
+							\begingroup
+								\catcode`\{=1 \catcode`\}=2 \catcode`\#=6 \catcode`\\=0 \catcode`\$=3
+								\catcode`\f=11 \catcode`\ =10
+								\def\idxmp{%
+									\relax
+									\edef\saved at at@catcode{\the\catcode`\@}%
+									\catcode`\@11
+									\@ifstar
+										{\let\print at idx\@gobble\index at macro@perso}
+										{\let\print at idx\@gobble\index at macro@perso}%
+								}%
+								\def\idx{%
+									\relax\makeatletter
+									\@ifstar
+										{\let\print at idx\@gobble\idx@}%
+										{\let\print at idx\@gobble\idx@}%
+								}%
+								\scantokens{##1}%
+							\endgroup
+							}% \xE9chappement \xA4...\xA4
+					\defactive\%{\unexpanded{\@commenttrue\itshape\color{codegray}\%}}% commentaire
+					\defactive\^^M{\unexpanded{\if at comment\normalfont\ttfamily\color{black}\fi\@commentfalse}\par\leavevmode}% retour charriot
+					\normalfont\renewcommand*\ttdefault{LinuxLibertineMonoTCC-TLF}\ttfamily
+					\setbox\z@\hbox{0}\edef\tt at spc{\hskip\the\wd\z@\relax}%
+					\catcode`\ =13
+					\begingroup
+						\lccode`\~`\ \relax
+						\lowercase{\endgroup\let~\tt at spc}%
+					\defactive\^^I{\tt at spc\tt at spc}% tabulation
+					\defactive\,{\string,{}}% ligatures
+					\defactive\<{\string<{}}%
+					\defactive\>{\string>{}}%
+					\defactive\-{\string-{}}%
+					\defactive\`{\string`{}}%
+					\defactive f{\string f{}}%
+					\showcodeactivechars% \xE9ventuelles modif de caract\xE8res actifs
+					\endlinechar-1
+					\scantokens\expandafter{\showcode at code}%
+				\endgroup
+				\removelastskip\par\nointerlineskip\nobreak
+				\ligneH{\kern4pt }%
+				\par%\nobreak
+				\if at errcode\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
+					{\ttfamily\err at message}
+					{\catcode`\\xA4=13
+					\begingroup
+						\lccode`\~`\\xA4\relax
+						\lowercase{\endgroup\def~##1~}{}%
+					\xdef\showcodehisze{\the\hsize}%
+					\newlinechar`\^^M
+					\saved at state
+					\microtypesetup{expansion=false,protrusion=false,tracking=false}%
+					\aux at code
+					\edef\nstiflevel at a{\number\currentiflevel}%
+					\scantokens\expandafter{\execcode at code}\relax
+					\edef\nstiflevel at b{\number\currentiflevel}%
+					\ifnum\nstiflevel at a=\nstiflevel at b\relax\else\errmessage{Erreur de if : \number\code at count}\fi
+					}%
+				\par\nointerlineskip\nobreak
+			\endgroup
+		\endMakeFramed
+		\restorevbadness
+	\endgroup
+	\medbreak
+}
+
+\newcommand*\ligneH[2][4pt]{%
+	\vbox{\offinterlineskip\hsize\linewidth
+		\null
+		#2%
+		\hrule width\linewidth\kern#1\relax\null% 4pt = espace entre ligne et ce qu'il y a dessous
+	}%
+}
+
+\newcommand*\gray at line{%
+	\everypar\expandafter{%
+		\the\everypar
+		\edef\color at line{\noexpand\colorbox{gray!\ifodd\code at line 35\else 20\fi}}% ou "50\else 35" pour l'impression
+		\setbox\strut at box\hbox{\vphantom{\xC0pj}}%
+		\dp\strut at box\dimexpr\dp\strut at box+1.25pt\relax
+		\ht\strut at box\dimexpr\ht\strut at box+1.25pt\relax
+		\setbox\strut at box\hbox{%
+			\fboxsep\z@
+			\color at line{\box\strut at box\kern\dimexpr\linewidth-7.5pt\relax}%
+		}%
+		\wd\strut at box\z@
+		\dp\strut at box\dimexpr\dp\strut at box-1.25pt\relax
+		\ht\strut at box\dimexpr\ht\strut at box-1.25pt\relax
+		\box\strut at box
+	}%
+}
+
+\newcommand*\num at code{%
+	\hb at xt@7.5pt{%
+		\hss
+		\global\advance\code at line\@ne
+		\tiny\number\code at line
+		\kern2.5pt}%
+}
+
+\newcommand*\defline[1]{\xdef#1{\number\code at line}}
+%|                                                                            |
+%|                               fin \showcode                                |
+%|____________________________________________________________________________|
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                   Mise en forme tdm, sectionnement                         |
+%|                                                                            |
+\usepackage{titletoc}
+
+\newcommand*\partminitoc{%
+	\edef\parksip at saved{\the\parskip}\parskip0pt
+	\vspace{1.5cm}%
+	\normalsize\normalfont
+	\startcontents[part]
+	\begingroup
+		\noindent\bfseries\large
+		Sommaire\hfill\null\par\vskip3pt
+	\endgroup
+	\hrule height1pt depth0pt
+	\smallskip
+	\renewcommand*\l at chapter[2]{%
+		\ifnum\c at tocdepth>\m at ne
+			\addpenalty{-\@highpenalty}%
+			\vskip 2pt \@plus\p@
+			\@tempdima1.5em
+			\begingroup
+			\parindent \z@ \rightskip \@pnumwidth
+			\parfillskip-\@pnumwidth
+			\leavevmode \normalfont
+			\advance\leftskip\@tempdima
+			\hskip-\leftskip
+			{##1}\nobreak\dotfill\nobreak\hb at xt@\@pnumwidth{\hss ##2}\par
+			\penalty\@highpenalty
+			\endgroup
+		\fi
+	}
+	\printcontents[part]{part-}{0}{\setcounter{tocdepth}{0}}%
+	\vskip5pt
+	\hrule height1pt depth0pt%\titlerule[1pt]
+	\parskip\parksip at saved\relax
+}
+
+\def\defpartcomment{\def\part at comment}
+\defpartcomment{}
+
+\renewcommand*\partformat{%
+	\normalfont\large\sffamily\bfseries\scshape
+	\hfill\MakeUppercase{\partname}\hfill\null
+	\vskip.5cm
+	\setbox\z@\hbox{\normalfont\Huge\sffamily\bfseries
+			\libLegacyGlyph{uniE007}%
+			}%
+		\hfill
+		\ifnum\c at part>0
+			{\normalfont\Huge\sffamily\bfseries
+			\libLegacyGlyph{uniE007}%
+			}%
+		\else
+			\vphantom{\box\z@}%
+		\fi
+		\hfill\null\endgraf
+		\fontsize{20}{20}\selectfont\centering
+}
+
+\renewcommand*\partheadendvskip{%
+	\partminitoc
+	\vfill
+	\unless\ifx\part at comment\@empty
+		\noindent\hfill
+		\begin{minipage}{0.65\linewidth}
+			\biolinum
+			\rightskip0pt \leftskip0pt \parindent\z@
+			\hsize5cm
+			\small\null\part at comment\par
+		\end{minipage}%
+		\global\let\part at comment\@empty
+		\vskip2cm
+	\fi
+}
+\addtokomafont{chapterprefix}{\raggedleft}
+\addtokomafont{chapter}{\huge\bfseries\scshape\raggedleft}
+\renewcommand*\chapterformat{%
+	\hfill
+	\hbox{\normalfont\bfseries\Large\color{gray}\chapappifchapterprefix{\nobreakspace}\fontsize{72}{80}\selectfont\lower .5ex\hbox{\thechapter}}
+	\vskip1cm
+}%
+\renewcommand*\chapterheadendvskip{\vskip2cm }
+\renewcommand*\chapterheadstartvskip{\vskip0.2\vsize}
+%|                                                                            |
+%|                 fin mise en forme tdm, sectionnement                       |
+%|____________________________________________________________________________|
+
+\usepackage[french]{babel}
+\frenchbsetup{StandardLists=true,og=\xAB,fg=\xBB}
+\selectlanguage{french}
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                   Mise en forme notes bas de page                          |
+%|                                                                            |
+\parindentFFN\parindent
+%|                                                                            |
+%|                 fin mise en forme notes bas de page                        |
+%|____________________________________________________________________________|
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                                  Index                                     |
+%|                                                                            |
+\usepackage{imakeidx}% index multiples
+\makeindex[
+	title=Index g\xE9n\xE9ral,
+	columns=2,
+	intoc=true,
+	program=texindy,
+	options=-M xindstyle.xdy -L french
+]
+\indexsetup{toclevel=part}
+\makeindex[
+	name=macros,
+	title=Index des macros d\xE9finies dans ce livre,
+	columns=2,
+	intoc=true,
+	program=texindy,
+	options=-M xindstyle.xdy -L french
+]
+
+\immediate\openout\wtest=xindstyle.xdy
+
+\exactwrite\wtest|(require "page-ranges.xdy")
+(define-location-class "arabic-page-numbers"
+                       ("arabic-numbers") :min-range-length 1)
+(markup-locclass-list :open "\quad " :sep ", ")
+(define-attributes (("etc")))
+(markup-locref :open "\hyperpage{" :close "}, \ldots" :attr "etc")
+(define-crossref-class "voir" :unverified)
+(markup-crossref-list :class "voir" :open "\textit{voir} " :sep ", ")
+(define-crossref-class "voiraussi" :unverified)
+(markup-crossref-list :class "voiraussi" :open "\textit{voir aussi} " :sep ", ")
+(define-location-class-order (
+   "roman-page-numbers"
+   "arabic-page-numbers"
+   "alpha-page-numbers"
+   "Roman-page-numbers"
+   "Alpha-page-numbers"
+   "see"
+   "voir"
+   "voiraussi"))
+(markup-locref :open "\hyperpage{" :close "}")
+(markup-locref :open "\hyperpage{" :close "}" :attr "hyperpage")|
+
+\immediate\closeout\wtest
+\usepackage{xstring}
+
+\let\list at macro@perso\empty% liste des macros perso d\xE9j\xE0 rencontr\xE9es
+
+\catcode`\W=3
+\def\noindexlist{W}% liste des entr\xE9es \xE0 ignorer lors de la mise en index
+
+\long\def\forbidindex#1{% n'indexe plus l'entr\xE9e "#1" jusqu'\xE0 ordre contraire
+	\expandafter\global\expandafter\long\expandafter\def\expandafter\noindexlist\expandafter{\noindexlist#1W}% ajoute l'entr\xE9e \xE0 la liste
+}
+
+\long\def\allowindex#1{% autorise l'index de l'entr\xE9e "#1"
+	\long\def\allowindex at i##1W#1W##2\allowindex at i{\global\long\def\noindexlist{##1W##2}}%
+	\expandafter\ifin\expandafter{\noindexlist}{W#1W}%
+		{\allowindex at i#1\allowindex at i}%
+		{}%
+}
+\catcode`\W=11
+
+\newcommand\idxmp{%
+	\relax
+	\edef\saved at at@catcode{\the\catcode`\@}%
+	\catcode`\@11
+	\@ifstar{\let\print at idx\@gobble\index at macro@perso}{\let\print at idx\@firstofone\index at macro@perso}%
+}
+
+\let\oldparagraph=\xA7
+\letactive \xA7\idxmp
+
+\def\index at macro@perso#1{%
+	\edef\temp@{\noexpand\substtocs\noexpand\temp@{\string#1}{\string @}}\temp@{\char64 }%
+	\edef\temp@{\expandafter\gobone\temp@}%
+	\exptwoargs\ifin\list at macro@perso{\string#1}%
+		{\print at idx{\leavevmode\hbox{\texttt{\string#1}}}% macro d\xE9j\xE0 rencontr\xE9e
+		}
+		{\xdef\list at macro@perso{\list at macro@perso\string#1}% premi\xE8re apparition
+		\print at idx{\leavevmode\hbox{\texttt{\string#1}${}^{{}\scriptscriptstyle\star{}}$}}%
+		}%
+	\index at macro@perso at i
+}
+
+\newcommand*\index at macro@perso at i[1][]{%
+	\index[macros]{\temp@ @\texttt{\char92 \temp@}#1}%
+	\restoreexpandmode
+	\catcode`\@=\saved at at@catcode\relax
+	\xspace
+}
+
+\edef\print at macro@list{\string\LaTeX\string\eTeX}
+
+\let\list at indexentry\empty% liste des entr\xE9es d'index
+
+\def\left@@of#1#2{% dans la sc #1, garde ce qui est \xE0 gauche de #2
+	\def\left@@of at i##1#2##2\@nil{\def#1{##1}}%
+	\expandafter\left@@of at i#1#2\@nil
+}
+
+\newcommand\add at toindexentry[1]{% ajoute #1 \xE0 la liste d'entr\xE9es ou pas
+	\edef\temp@{\detokenize\expandafter{\string#1}}%
+ 	\expandafter\left@@of\expandafter\temp@\string|% ne prend que ce qui est avant |
+ 	\expandafter\left@@of\expandafter\temp@\string!% ne prend que ce qui est avant !
+	\exptwoargs\ifin{\list at indexentry}{\temp@,}
+		\relax
+		{\xdef\list at indexentry{\list at indexentry\temp@, }}%
+}
+
+\newcommand\idx{\relax\makeatletter\@ifstar{\let\print at idx\@gobble\idx@}{\let\print at idx\@firstofone\idx@}}
+
+\catcode`\W=3
+\newcommand\idx@[2][]{%
+	\saveexpandmode\expandarg
+	\let\savedindex\index
+	\expandafter\ifin\expandafter{\noindexlist}{W#2W}{\let\index\gobone}{}%
+	\expandafter\if at controlsequence\expandafter{\firstto at nil#2\@nil}% si #2 est une s\xE9quence de contr\xF4le\xA4\xA7*\firstto at nil\xA4
+		{\let\repeat\relax
+		\add at toindexentry{#2}%
+		\edef\temp@{\expandafter\gobone\string#2}%
+		\long\edef\temp at a{\meaning#2}%
+		\long\edef\temp at b{\string#2}%
+		\let\xx at space\xspace
+		\ifx\temp at a\temp at b% si #2 est une primitive
+			\expandafter\ifx\firstto at nil#2\@nil\ % #2 = \<espace> ?
+				\index{\char\number`#2 @\quitvmode\hbox to0pt {\hss${}^*$}\texttt{\char92 \char32 }#1}%
+				\print at idx{\texttt{\char92 \char32 }}%
+			\else
+				\index{\temp@ @\quitvmode\hbox to0pt {\hss${}^*$}\texttt{\char92 \temp@}#1}%
+				\print at idx{\texttt{\char92 \temp@}}%
+			\fi
+		\else
+			\expandafter\expandafter\expandafter\ifempty
+			\expandafter\expandafter\expandafter{\expandafter\gobtwo\string#2}% si caract\xE8re de contr\xF4le
+				{\index{\char\number\expandafter`\temp@ "@@\texttt{\char92 \char\number\expandafter`\temp@}#1}%
+				\print at idx{\texttt{\char92 \temp@}}%
+				\let\xx at space\relax
+				}%
+				{\StrSubstitute\temp@{\string @}{\char64 }[\temp@]% remplace les @
+				\IfSubStr\print at macro@list{\string#2}%
+					{\index{\temp@ @\protect#2#1}% si macro dans liste
+					\print at idx{#2}%
+					}%
+					{\index{\temp@ @\texttt{\char92 \temp@}#1}%
+					\print at idx{\texttt{\char92 \temp@}}%
+					}%
+				}%
+		\fi
+		\restoreexpandmode
+		\let\repeat\fi
+		\makeatother
+		\let\index\savedindex
+		\xx at space
+		}%
+		{\restoreexpandmode
+		\index{#2\ifx\@empty#1\@empty\else #1\fi}%
+		\print at idx{#2}%
+		\let\index\savedindex
+		\makeatother
+		}%
+}
+\catcode`\W=11
+
+\newcommand\if at controlsequence[1]{%
+	\begingroup
+		\escapechar`\\
+		\edef\first at char{\expandafter\firstto at nil\string#1\@nil}%\xA4
+		\edef\escape at char{\expandafter\firstto at nil\string\relax\@nil}%
+		\ifx\first at char\escape at char
+			\endgroup\expandafter\firstoftwo
+		\else
+			\endgroup\expandafter\secondoftwo
+		\fi
+}
+
+\def\visiblespace{ }
+
+% met en index un seul caract\xE8re de la forme <char> ou \<char>
+\newcommand\cidx{\relax\@ifstar{\let\print at idx\@gobble\cidx@}{\let\print at idx\@firstofone\cidx@}}
+\newcommand\cidx@[2][]{%
+	\if at controlsequence{#2}% si c'est une macro
+		{\ifnum`#2=`\ % espace ?
+			\index{\char\number`#2 @\textvisiblespace#1}%
+			\add at toindexentry{ }%
+			\print at idx{\texttt{\char92 \char32 }}%
+		\else
+			\index{\char\number`#2 @\texttt{\char\number`#2}#1}%
+			\expandafter\add at toindexentry\expandafter{\expandafter\char\number`#2}%
+			\print at idx{\texttt{\char\number`#2}}%
+		\fi
+		\xspace
+		}
+		{\StrSubstitute{#2}"{""}[\temp@@]%
+		\index{\temp@@ @\texttt{\string#2}#1}%
+		\add at toindexentry{#2}%
+		}%
+}
+
+\def\idxdetokenize{\begingroup\catcode`\^12 \idxdetokenize at i}
+\def\idxdetokenize at i#1{\endgroup\detokenize{#1}}
+% met en index le second argument "d\xE9tok\xE9niz\xE9"
+\newcommand\verbidx{\begingroup\catcode`\^12 \@ifstar{\let\print at idx\@gobble\verbidx@}{\let\print at idx\@firstofone\verbidx@}}
+\newcommand\verbidx@[2][]{%
+	\index{#2@{\ttfamily\protect\idxdetokenize{#2}}#1}%
+	\print at idx{{\ttfamily\idxdetokenize{#2}}}%
+	\add at toindexentry{#2}%
+	\endgroup
+}
+
+% met en index les primitives de test "\if...", "\else", "\fi"
+\newcommand\tidx{\relax\@ifstar{\let\print at idx\@gobble\tidx at i}{\let\print at idx\@firstofone\tidx at i}}
+\newcommand\tidx at i[2][]{% #2 est le nom de la primitive SANS le caract\xE8re d'\xE9chappement
+	\index{#2@\quitvmode \hbox to0pt {\hss ${}^*$}\texttt{\char92 #2}#1}%
+	\add at toindexentry{#2}%
+	\print at idx{\texttt{\char92 #2}}%
+}
+%|                                fin index                                   |
+%|____________________________________________________________________________|
+
+\let\grandsaut\bigbreak
+\newdimen\main at parindent
+
+\usepackage[
+	hyperindex    = false,
+	plainpages    = true,
+	pdfauthor     = {Christian~TELLECHEA},
+	pdftitle      = {Apprendre~\xE0~programmer~en~TeX},
+	pdfsubject    = {Pr\xE9sentation~des~concepts~de~base~et~apprentissage~de~la~programmation~en~langage~TeX},
+	pdfcreator    = {LaTeX}
+	]{hyperref}
+
+\@addtoreset{chapter}{part}
+
+\makeatother
+\begin{document}
+\defactive\xAB{\char19 \penalty10000 \FBguillspace\relax\ignorespaces}%
+\defactive\xBB{\unskip\penalty10000 \FBguillspace\relax\char20 }%
+\pagestyle{scrheadings}%
+\parindent=15pt
+\parskip0pt plus.3pt
+\hyphenation{cons-truire cons-truite cons-truites cons-truction cons-tructions cons-truit exem-ple exem-ples con-state con-stater con-sta-ta-tion}%
+\widowpenalty=600
+\clubpenalty=600
+\interfootnotelinepenalty=10000
+\csname main at parindent\endcsname=\parindent
+\let\oldit=\it \let\it=\itshape
+\let\oldbf=\bf \let\bf=\bfseries
+\let\oldrm=\rm \let\rm=\normalfont
+\let\oldtt\tt \let\tt=\ttfamily
+\let\oldsc=\sc \let\sc=\scshape% \xE9viter les avertissements d'obsolescence
+\raggedbottom
+\newcommand\drawbox[1]{%
+	\leavevmode
+	\begingroup
+	\tikz\draw[fill,black,overlay](0.35pt,0pt)circle(1pt);%
+	\fboxsep0pt \fboxrule0.2pt
+	\kern-\fboxrule\fbox{#1}\kern-\fboxrule
+	\endgroup}
+\def\messageavert{message d'avertissement}
+\startcontents[tableofcontents]
+\startcontents[part]
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                               D\xE9but du livre                               |
+%|                                                                            |
+\frontmatter
+\pagestyle{empty}
+\null\pagebreak
+\null\pagebreak
+%%%%%%%%%%%% Page de titre %%%%%%%%%
+\title{\huge Apprendre \xE0 programmer en \TeX{}}
+\author{\small Christian \textsc{Tellechea}}
+\date{\small Septembre 2014}
+\def\largeurtext{85}%
+\uppertitleback{%
+	\leavevmode\null\hfill
+	\vtop{%
+		\hsize=.\largeurtext\textwidth
+		\footnotesize
+		\parskip=3pt
+		Ce livre est \xAB auto\xE9dit\xE9 \xBB, c'est-\xE0-dire que la conception, les relectures et les corrections ont \xE9t\xE9 faites par l'auteur. Malgr\xE9 le soin qui y a \xE9t\xE9 apport\xE9, des fautes et des erreurs peuvent encore exister.
+
+		Toute erreur, omission ou toute proposition d'am\xE9lioration peut \xEAtre signal\xE9e.\medbreak
+
+		Email de l'auteur :\par
+		\href{mailto:unbonpetit at netc.fr}{\texttt{unbonpetit at netc.fr}}\bigbreak
+		
+		D\xE9p\xF4t du code source, fichiers pdf et fichiers annexes :\par
+		\href{https://framagit.org/unbonpetit/apprendre-a-programmer-en-tex/}{\texttt{https://framagit.org/unbonpetit/apprendre-a-programmer-en-tex/}}\bigbreak
+		
+		Remont\xE9es de bugs, am\xE9liorations :\par
+		\href{https://framagit.org/unbonpetit/apprendre-a-programmer-en-tex/issues}{\texttt{https://framagit.org/unbonpetit/apprendre-a-programmer-en-tex/issues}}
+		\vskip1.5cm
+		
+		Les codes et algorithmes figurant dans ce livre sont donn\xE9s sans \emph{aucune garantie} en vue de leur utilisation dans le cadre d'une activit\xE9 professionnelle ou commerciale.
+	}%
+	\hfill\null
+}
+
+\lowertitleback{%
+	\leavevmode\null\hfill
+	\vtop{%
+		\hsize=.\largeurtext\textwidth
+		\small
+		ISBN 978-2-9548602-0-6\medskip
+
+		\textcopyright{} Christian \textsc{Tellechea}, 2014\medskip
+		
+		\scriptsize
+		R\xE9vision \no2a, 26/04/2019\medskip
+		
+		Photo couverture \textcopyright{} Christian~\textsc{Tellechea}\par
+		Photo 4\ieme{} couverture \textcopyright{} Willi~\textsc{Heidelbach}.
+		\medbreak
+		Le code source au format texte, ce fichier au format pdf qui en r\xE9sulte apr\xE8s compilation, les fichiers au format texte g\xE9n\xE9r\xE9s par la compilation ainsi que les fichiers texte et pdf n\xE9cessaires \xE0 la compilation sont plac\xE9s sous la licence \xABLaTeX Project Public License Version 1.2\xBB qui est consultable \xE0 l'adresse suivante \href{https://www.latex-project.org/lppl/lppl-1-2.txt}{\texttt{https://www.latex-project.org/lppl/lppl-1-2.txt}}
+	}%
+	\hfill\null
+}
+
+\dedication{%
+	\vskip3cm
+	\hfill
+	\vtop{%
+		\hsize=.47\linewidth
+		\parindent=0pt
+		\raggedleft\itshape\small
+		Un langage de programmation est cens\xE9 \xEAtre une fa\xE7on conventionnelle de donner des ordres \xE0 un ordinateur. Il n'est pas cens\xE9 \xEAtre obscur, bizarre et plein de pi\xE8ges subtils (\xE7a, ce sont les attributs de la magie).\medskip
+
+		\normalfont Dave \textsc{Small}%
+	}%
+}
+
+\extratitle{%
+	\null\vskip0pt plus1fill
+	\hfill
+	\hbox{\Large\biolinum Apprendre \xE0 programmer en \TeX{}}%
+	\hfill\null
+	\vskip0pt plus3fill
+	\null
+}
+
+\maketitle
+
+\pagestyle{plain}\setcounter{page}{1}
+\chapter*{Pr\xE9face}
+
+Il est d\xE9j\xE0 bien difficile de maitriser \TeX{} comme langage de composition\ldots{} C'est un vrai d\xE9fi que d'en connaitre suffisamment les m\xE9andres pour l'utiliser comme langage de programmation\footnote{\TeX{} a \xE9t\xE9 cr\xE9\xE9 pour la composition et si son cr\xE9ateur l'a \xE9t\xE9 dot\xE9 de ce qu'il faut pour programmer, ce n'est pas par choix, mais parce qu'il a \xE9t\xE9 oblig\xE9 de le faire (un peu \xE0 contrec\oe ur) !}. Et, c'est une mission quasi impossible que d'\xE9crire un livre l\xE0-dessus, j'en parle en connaissance de cause ! D'ailleurs, bien peu de choses existent sur le sujet. Non pas que les gens sachant programmer en \TeX{} soient rares, ils sont simplement assez sages et modestes pour ne pas s'embarquer dans une telle gal\xE8re. Inconscient, insouciant et trop s\xFBr de moi, j'ai commenc\xE9 \xE0 \xE9crire sans mesurer les difficult\xE9s auxquelles j'allais me heurter. Je ne sais toujours pas quelle folie m'a pouss\xE9 \xE0 poursuivre cette aventure jusqu'au bout. M\xEAme si un peu de vanit\xE9 a certainement jou\xE9 un r\xF4le, ma motivation n'a jamais \xE9t\xE9 de montrer que \xAB moi, je peux \xBB; il ne s'agit pas d'un p\xE9ch\xE9 d'orgueil. Le but poursuivi, moteur plus fort que les difficult\xE9s rencontr\xE9es au cours de cette aventure, a \xE9t\xE9 d'aider ceux qui, comme moi lorsque j'\xE9tais d\xE9butant en programmation \TeX, restent devant un code \xE9crit en \TeX{} comme devant un texte en chinois ancien : plong\xE9s dans un abime d'incompr\xE9hension.
+
+\Qu iconque connait un peu \TeX{} a d\xFB sourire en lisant la citation de Dave~\textsc{Small}. Et a d\xFB se dire qu'avec \TeX{} bien plus qu'avec d'autres langages, on allait forc\xE9ment parler de magie noire \xE0 un moment ou \xE0 un autre ! Car il est vrai que \TeX{} est un langage difficile, tortueux et r\xE9put\xE9 comme tel. On ne compte plus ceux qui font tout pour ne pas s'y frotter, ceux qui le ha\xEFssent ou le rejettent ni ceux qui, bien que l'utilisant, se traitent de fous tant des choses apparemment simples sont en r\xE9alit\xE9 compliqu\xE9es. \TeX{} est bourr\xE9 de d\xE9fauts, collectionne les lacunes, a une syntaxe \xE0 coucher dehors tant elle est irr\xE9guli\xE8re, mais malgr\xE9 tout cela, on se prend \xE0 l'appr\xE9cier un peu comme on pourrait appr\xE9cier les d\xE9fauts d'un ami de longue date, taciturne et bourru. Tout comme cet ami pourrait envier certains c\xF4t\xE9s aux \xAB nouveaux communicants \xBB dont nous sommes d\xE9sormais entour\xE9s, \TeX{} ne soutient pas non plus la comparaison avec les langages modernes. Mais, l'utiliser pour programmer procure un plaisir certain ainsi qu'une sensation de libert\xE9 et de cr\xE9ativit\xE9 qu'on ne retrouve que dans une moindre mesure avec les langages de programmation r\xE9cents.
+
+J'invite donc mon lecteur, arm\xE9 de patience et de pers\xE9v\xE9rance, \xE0 entreprendre ce p\xE9riple qui s'annonce ardu, mais riche de nouveaut\xE9s et d'originalit\xE9. La meilleure chose que je lui souhaite est d'arriver \xE0 ses fins et par l\xE0 m\xEAme, atteindre aussi le but dans lequel ce livre a \xE9t\xE9 \xE9crit : acqu\xE9rir une autonomie dans la programmation en \TeX. Ce livre, qui n'est qu'une simple introduction \xE0 la programmation en \TeX, sera peut-\xEAtre un d\xE9part pour de nouveaux horizons qui, apr\xE8s beaucoup de pratique et sans utilisation de magie noire --~c'est garanti !~--, le m\xE8neront, qui sait, \xE0 devenir un \TeX gourou\ldots
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                             Table des mati\xE8res                             |
+%|                                                                            |
+\cleardoublepage
+%%%%%%%%% Table des mati\xE8res %%%%%%%
+\begingroup
+	\huge\centering
+	{\null\vspace{2cm}\bfseries\scshape Table des mati\xE8res}\par
+	{\Huge\bfseries\libLegacyGlyph{uniE007}}\bigbreak
+	\normalfont\normalsize
+	\makeatletter
+	\renewcommand*\l at chapter{\@dottedtocline{0}{0em}{1.5em}}
+	\printcontents[tableofcontents]{sommaire-}{-1}{\setcounter{tocdepth}{2}}
+	\clearpage
+\endgroup
+%|                                                                            |
+%|                           Fin table des mati\xE8res                           |
+%|____________________________________________________________________________|
+
+\pagestyle{scrheadings}
+\mainmatter
+
+\chapter*{Conventions adopt\xE9es dans ce livre}
+\addcontentsline{toc}{part}{Conventions adopt\xE9es dans ce livre}
+
+\subsubsection{Les codes}
+Par souci de p\xE9dagogie, les codes sont tr\xE8s nombreux. Ils sont pr\xE9sent\xE9s de telle sorte que le code pr\xE9c\xE8de l'affichage qu'il g\xE9n\xE8re. En voici un, le premier d'une longue s\xE9rie :
+
+\showcode/Voici le code en \TeX{} du premier exemple.% ceci est un commentaire
+
+On peut observer l'affichage qu'il produit juste au-dessous !/%
+
+Sauf pour des cas tr\xE8s exceptionnels qui seront signal\xE9s, il ne peut y avoir de \xABtriche\xBB sur l'affichage : il est tr\xE8s exactement le r\xE9sultat du code qui se trouve au-dessus. En effet, les codes sont tap\xE9s \emph{une seule fois} dans le code source de ce livre. Une macro est charg\xE9e de stocker ce code pour ensuite fonctionner en deux temps. Elle l'affiche tel quel dans la partie haute du cadre puis laisse \TeX{} le compiler et afficher le r\xE9sultat dans la partie basse.
+
+Les codes donn\xE9s produisent donc les r\xE9sultats affich\xE9s, mais le lecteur doit garder en t\xEAte les limitations suivantes :
+
+\begin{itemize}
+	\item malgr\xE9 les relectures effectu\xE9es sur chaque code, ils ne sont pas garantis sans \xABbogue\xBB. Certains bogues \xE9tant particuli\xE8rement difficiles \xE0 d\xE9busquer, il serait m\xEAme tr\xE8s \xE9tonnant que certains n'en contiennent pas !
+	\item dans la plupart des cas, les codes donn\xE9s ne sont qu'une fa\xE7on de faire \emph{parmi beaucoup d'autres}, le nombre d'alternatives tendant \xE0 augmenter avec la complexit\xE9 de la t\xE2che \xE0 ex\xE9cuter. Ces codes sont donc \xE0 consid\xE9rer comme \emph{une} solution et non pas comme \emph{la} solution. Ils n'ont donc pas valeur de m\xE9thode absolue qui serait meilleure que toute autre;
+	\item ils ne fonctionnent que pour un certain domaine de validit\xE9 (souvent implicite) des arguments de leurs macros, car \xE9largir ce domaine suppose des complications qu'il est long et fastidieux de programmer. On peut donc toujours trouver des cas plus ou moins sp\xE9ciaux o\xF9 les arguments contiennent des choses qui feront \xABplanter\xBB une macro.
+	
+	Par exemple, si une macro attend un nombre entier et qu'on lui donne la lettre \xABa\xBB comme argument, \TeX{} va protester avec l'erreur \xAB\texttt{missing number}\xBB. Par ailleurs, des caract\xE8res sp\xE9ciaux comme \xAB\verb|#|\xBB seul, \xAB\verb|%|\xBB, etc. vont in\xE9vitablement provoquer des plantages s'ils sont \xE9crits dans les arguments des macros. Sauf dans les cas o\xF9 ces caract\xE8res sp\xE9ciaux sont g\xE9r\xE9s, les macros attendent des arguments \xABgentils\xBB, c'est-\xE0-dire constitu\xE9s de caract\xE8res ayant un code de cat\xE9gorie de 10, 11 ou 12 (voir page~\pageref{catcode.table}); 
+	\item les codes propos\xE9s ne sont pas toujours \emph{optimis\xE9s}, c'est-\xE0-dire que leur vitesse d'ex\xE9cution tout comme la consommation de m\xE9moire qu'ils requi\xE8rent peuvent \xEAtre am\xE9lior\xE9es. Ils r\xE9pondent avant tout \xE0 deux contraintes, celle d'illustrer la notion qui est en train d'\xEAtre abord\xE9e tout en utilisant des notions pr\xE9c\xE9demment vues et celle de ne pas inutilement compliquer le code.
+\end{itemize}
+
+J'invite le lecteur \xE0 \emph{lire} les codes propos\xE9s, m\xEAme s'ils sont r\xE9barbatifs. Lire n'est pas survoler ! Lorsque les codes deviennent assez complexes, il faut vraiment faire un effort mental important et se plonger dedans afin de comprendre comment ils fonctionnent. Les commentaires ins\xE9r\xE9s dans le code, toujours tr\xE8s nombreux, fournissent une aide pour cela, mais la gymnastique mentale consistant \xE0 analyser l'enchainement des instructions et comprendre comment \xE9voluent les arguments des macros reste n\xE9cessaire.
+
+\subsubsection{Les exercices}
+Les exercices, \xE9galement en grand nombre et de difficult\xE9 variable, sont souvent propos\xE9s au lecteur au fur et \xE0 mesure que de nouvelles notions sont pr\xE9sent\xE9es. Ils sont pr\xE9c\xE9d\xE9s d'un \xAB{\footnotesize\rule{1.25ex}{1.25ex}}\xBB et imm\xE9diatement suivis de leur solution, choix discutable, mais qui s'est impos\xE9. Voici \xE0 ce propos le premier exercice :
+
+\begin{exercice}
+\Qu el argument principal peut-on trouver pour justifier que les exercices soient imm\xE9diatement suivis de la solution ?
+
+\solution
+Se d\xE9cider a \xE9t\xE9 difficile, mais qu'y a-t-il de plus lassant que de passer son temps \xE0 tourner les pages pour aller d\xE9busquer \xE0 la fin du livre la solution d'un exercice que, bien souvent, on n'arrive pas \xE0 r\xE9soudre ? Ou qu'on ne \emph{souhaite} pas r\xE9soudre ! Sur ce point, l'exp\xE9rience un peu p\xE9nible du \TeX book (que vous avez bien s\xFBr d\xE9j\xE0 lu et relu !) a \xE9t\xE9 d\xE9cisive et m'a pouss\xE9 \xE0 pr\xE9senter les choses diff\xE9remment. Il me semble que le lecteur, suppos\xE9 adulte et ayant un certain contr\xF4le de lui-m\xEAme, peut se retenir de lire la solution s'il souhaite vraiment chercher un exercice.
+\end{exercice}
+
+\subsubsection{\xC9l\xE9ments de code}
+Les chevrons ''$\lcodedelim$`` et ''$\rcodedelim$`` ont vocation \xE0 symboliser des \xE9l\xE9ments dont la nature est exprim\xE9e par les mots se trouvant entre ces chevrons. Ainsi, \verb|<nombre>| est cens\xE9 repr\xE9senter\ldots{} un nombre ! Selon la m\xEAme notation, on aurait \verb|\<macro>|, \verb|<texte>|, \verb|<code>| (pour du code source en \TeX{}), \verb|<car>| (pour un caract\xE8re), \verb|<dimension>|, etc.
+\grandsaut
+
+Un espace dans le code source peut \xEAtre mis en exergue, soit parce qu'il rev\xEAt une importance particuli\xE8re, soit parce sa pr\xE9sence est importante et qu'il doit \xEAtre clairement \xEAtre visible. Dans ces cas, il est not\xE9 \xAB\verb*| |\xBB.
+
+Un caract\xE8re isol\xE9 peut parfois \xEAtre encadr\xE9 pour qu'il soit ais\xE9ment identifiable, comme l'apostrophe inverse \xAB{\def\boxtokensep{0.5pt}\boxtoken `}\xBB.
+
+Lorsqu'il peut y avoir ambig\xFCit\xE9 sur les caract\xE8res composant le nom d'une commande ou bien parce que nom contient des caract\xE8res inhabituels, le nom est encadr\xE9 comme dans \xAB\hbox{\verb|\|\fboxsep1pt \fbox{\ttfamily a\string_1\string\b7}}\xBB (car une commande peut tout \xE0 fait porter un nom pareil !).
+
+\subsubsection{Les macros propres \xE0 ce livre}
+Tout au long de ce livre, des macros sont d\xE9finies dans des codes ou dans des exercices. Lorsqu'elles sont d\xE9finies, elles sont suivies du signe \xAB$\star$\xBB mis en exposant comme dans \verb|\gobone|${}^{{}\star{}}$. Elles disposent d'un index \xE0 part (voir page~\pageref{index.macros}) o\xF9 l'on peut ais\xE9ment trouver le num\xE9ro de page o\xF9 chacune d'entre elles a \xE9t\xE9 mentionn\xE9e. Lorsqu'elles sont mentionn\xE9es dans l'index g\xE9n\xE9ral, elles sont \xE9galement suivies de \xAB$\star$\xBB.
+
+\subsubsection{Anglicismes}
+Si \xE0 mon grand regret l'anglais --~que dis-je, le \emph{globish} !~-- tend \xE0 s'imposer comme langue universelle de communication entre personnes ne parlant pas la m\xEAme langue, il s'est depuis longtemps impos\xE9 comme langue en programmation. Il est en effet ind\xE9niable que les mots-cl\xE9s de presque tous les langages de programmation sont en anglais. Ceci a conduit \xE0 employer des mots anglais pour d\xE9signer des notions couramment utilis\xE9es dans le monde de la programmation. J'ai donc fait le choix facile, pour quelques mots, d'utiliser la version anglaise.
+
+\begin{centrage}
+\footnotesize
+\begin{tabular}{>\itshape llp{0.55\linewidth}}\\\hline
+	\normalfont Anglais&Fran\xE7ais&Signification\\\hline
+	\idx{token}&entit\xE9 lexicale&s\xE9quence d'un ou plusieurs caract\xE8res du code source reconnue et assimil\xE9e par \TeX{} comme un \xE9l\xE9ment indivisible selon les r\xE8gles de l'analyseur lexical qui seront expos\xE9es dans ce livre.\\
+	tokenization&segmentation&s'applique \xE0 une portion du code source : transformation des caract\xE8res du code source en tokens.\\
+	catcode&code de cat\xE9gorie&s'applique \xE0 un token : entier sur 4 bits (0 \xE0 15) affect\xE9 \xE0 un token lorsqu'il est lu par \TeX.\\
+	\idx{package}&extension&mot g\xE9n\xE9rique signifiant \xAB fichier externe permettant d'accroitre les possibilit\xE9s de \TeX{} \xBB. Bien souvent, il s'agit de code source mettant \xE0 disposition des macros permettant de r\xE9aliser des t\xE2ches complexes.\\\hline
+\end{tabular}
+\end{centrage}
+
+\subsubsection{Les r\xE8gles}
+Au fur et \xE0 mesure de la progression, des r\xE8gles pr\xE9cisant la fa\xE7on de fonctionner de \TeX{} sont inscrites dans des cadres sur fond gris. Toutes ces r\xE8gles sont reprises en annexe \xE0 partir de la page~\pageref{recapregle}.
+
+\subsubsection{Orthographe rectifi\xE9e}
+Lorsque j'ai vu la moue un peu dubitative des rares personnes ayant lu quelques passages de ce livre, j'y ai vu l'embarras de ceux qui, me d\xE9couvrant incapable d'\xE9crire quelques phrases sans faute, se pr\xE9paraient \xE0 me faire des remarques sur mon orthographe fautive.
+
+J'ai fait le choix, comme l'indique le logo ci-dessous, d'utiliser l'orthographe rectifi\xE9e de la r\xE9forme de 1990.
+
+\begin{centrage}
+	\includegraphics[scale=0.3333]{vignette.png}
+\end{centrage}
+
+Par cons\xE9quent, la phrase \xAB \emph{nous sommes surs que la boite va disparaitre}\xBB est orthographiquement correcte. Il ne manque aucun accent circonflexe, m\xEAme s'il en fallait trois avant la r\xE9forme. \Qu e l'orthographe rectifi\xE9e soit encore actuellement consid\xE9r\xE9e comme fautive par la majorit\xE9 des personnes me laisse un peu interrogatif. Malgr\xE9 plus de deux d\xE9cennies pendant lesquelles elle a \xE9t\xE9 \emph{recommand\xE9e}, le fait qu'elle soit si peu reconnue et pratiquement absente de l'enseignement ne s'explique pour moi que par le rapport excessivement rigide et crisp\xE9 que nous entretenons avec notre orthographe.
+
+Bien \xE9videmment, ce livre \xE9tant 100\% \emph{fait-maison}, je ne peux le garantir exempt de coquilles, d'accords fautifs ou de lourdeurs. Je pr\xE9sente d'ores et d\xE9j\xE0 mes excuses \xE0 mes lecteurs pour les d\xE9sagr\xE9ments que cela leur procurera.
+%|                                                                            |
+%|                             Fin d\xE9but du livre                             |
+%|____________________________________________________________________________|
+
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                                Introduction                                |
+%|                                                                            |
+\addpart{Introduction}
+\chapter{\TeX{}, la brute et le truand}
+\section{Les sp\xE9cificit\xE9s de \TeX}
+Le programme \texttt{tex} est con\xE7u pour lire du code source (le plus souvent enregistr\xE9 dans un fichier de type \xABtexte\xBB) puis \xABcompiler\xBB ce code afin de produire un document affichable disponible dans un fichier de type \texttt{dvi}\idx*{fichier!dvi}. Un tel programme, transformant du code source en document affichable, est appel\xE9 \xAB\emph{\idx{moteur}}\footnote{On dit aussi parfois \xAB\emph{compilateur}\xBB.}\xBB. Le langage \TeX{}\footnote{Il ne faut pas confondre le \emph{moteur} \texttt{tex}\idx*{moteur!tex} qui est ex\xE9cut\xE9 par un ordinateur et le \emph{langage} \TeX{}. Ce langage met \xE0 disposition des commandes pour produire un document, mais aussi des commandes pour \emph{programmer}. C'est d'ailleurs le but de ce livre que d'expliquer comment utiliser ces derni\xE8res.} met \xE0 disposition des commandes qui sont appel\xE9es \emph{\idx{primitive}s}, tout en permettant de \emph{d\xE9finir} d'autres commandes, appel\xE9es \xAB\emph{macros-instructions}\xBB ou \xAB\emph{macros}\xBB. Compte tenu de leur puissance, ces derni\xE8res sont d'un emploi extr\xEAmement courant et sont donc pratiquement indispensables. Elles peuvent \xEAtre d\xE9finies par l'utilisateur \xE0 l'int\xE9rieur m\xEAme du code source, mais peuvent aussi \xEAtre contenues dans un fichier externe appel\xE9 extension ou \xAB\emph{\idx{package}}\xBB qui sera lu \xE0 un endroit du code source choisi par l'utilisateur. Derni\xE8re possibilit\xE9, des macros peuvent \xE9galement \xEAtre pr\xE9compil\xE9es pour \xEAtre incorpor\xE9es dans un ex\xE9cutable appel\xE9 \xAB\emph{\idx{format}}\xBB qui embarque le langage \TeX{} dans sa totalit\xE9 ainsi que des macros pr\xE9compil\xE9es. Ainsi, lorsqu'on lance l'ex\xE9cutable d'un format, ces macros sont d\xE9j\xE0 d\xE9finies avant que le d\xE9but du code source ne soit lu.
+
+Les formats les plus connus et les plus utilis\xE9s\footnote{On ne peut pas vraiment parler de fr\xE9quence d'utilisation des formats les plus \xAB c\xE9l\xE8bres \xBB, car n'importe qui peut se construire son propre \idx{format} \xE0 la carte. La man\oe uvre \xE0 suivre ne sera pas d\xE9crite dans ce livre.} sont :% TODO : v\xE9rifier qu'un saut de page n'a pas lieu ici
+
+\begin{itemize}
+	\item plain-\TeX\idx*{format!plain-\TeX}, dont l'ex\xE9cutable est \xAB\texttt{tex}\xBB, o\xF9 les macros \xAB\texttt{plain}\xBB ont \xE9t\xE9 d\xE9finies par l'auteur de \TeX{} lui-m\xEAme. Il est donc \xE0 noter que lorsqu'on lance le programme \texttt{tex}, en plus du langage \TeX{} \emph{nu}, on dispose aussi de toutes les macros de \texttt{plain};
+	\item \LaTeX\idx*{format!\LaTeX}, dont l'ex\xE9cutable est \xAB\texttt{latex}\xBB, qui est un recueil de macros, \xE9crites et mises en coh\xE9rence \xE0 l'origine par \idx*{Lamport Leslie}Leslie~\textsc{Lamport} et dont le but est de fournir des macros de haut niveau pour la composition;
+	\item Con\TeX t\idx*{format!Con\TeX t} qui est un peu \xE0 part des deux pr\xE9c\xE9dents en ceci qu'il n'est pas bas\xE9 sur le moteur \texttt{tex}\idx*{moteur!tex} mais sur un autre moteur permettant l'acc\xE8s au langage \emph{\idx{lua}};
+	\item pour m\xE9moire, en voici de tr\xE8s peu connus ou tr\xE8s anciens, mais qui ont le m\xE9rite d'exister : \texttt{phyzzx}, \texttt{psizzl}, \texttt{Lollipop} et \texttt{TeXsis}. Le plus original de la bande est sans doute \texttt{StarTeX} qui a une approche tr\xE8s \xE9loign\xE9e de tous les autres puisque la syntaxe des commandes se rapproche au plus pr\xE8s de celle de l'\texttt{HTML} !
+\end{itemize}
+
+Le langage \TeX{} et ses formats sont r\xE9put\xE9s produire des documents de grande qualit\xE9 typographique, mais \TeX{} est vieux. Son concepteur, \idx*{Knuth Donald}Donald~\textsc{Knuth}, l'a publi\xE9 en 1982\footnote{Une version plus r\xE9cente \xAB\TeX90\xBB a \xE9t\xE9 publi\xE9e en 1990 o\xF9 de nouvelles primitives ont \xE9t\xE9 incorpor\xE9es et o\xF9 la lecture du code est d\xE9sormais sur 8 bits au lieu de 7 pour \xAB\TeX82\xBB.}, \xE9poque o\xF9 aucun des langages \xAB modernes \xBB n'existait encore. Pour le programmer, il a utilis\xE9 un vieux langage s'il en est, le Pascal. \TeX{} est assur\xE9ment tr\xE8s stable, probablement exempt de bug, mais ind\xE9niablement \emph{tr\xE8s vieux} \xE0 l'\xE9chelle du temps informatique. On peut d'ailleurs s'\xE9tonner qu'entre 1982 et le d\xE9but des ann\xE9es 2000, une aussi longue p\xE9riode se soit \xE9coul\xE9e sans \xE9volution majeure. Certes, entre temps, un nouveau moteur \xAB\eTeX\idx*{moteur!etex}\xBB a vu le jour o\xF9 de nouvelles primitives ont ajout\xE9 des fonctionnalit\xE9s bien pratiques qui n'existaient pas dans le langage \TeX{} initial. Plus r\xE9cemment encore, le moteur \xABpdf\TeX\idx*{moteur!pdftex}\xBB a \xE9t\xE9 \xE9crit par H\xE0n Th\'{\xEA} \textsc{Th\xE0nh}\idx*{H\xE0n Th\xEA Th\xE0nh} et de nouvelles fonctionnalit\xE9s ont \xE9t\xE9 ajout\xE9es, tout en conservant celles de \eTeX\idx*{moteur!etex}. Mais ce qui fait la particularit\xE9 de pdf\TeX\idx*{moteur!pdftex} est qu'il est capable de produire \emph{directement} un fichier \verb|pdf|\idx*{fichier!pdf} \xE0 partir du code source sans passer par le fichier \texttt{dvi} jusqu'alors incontournable.
+\grandsaut
+
+Au-del\xE0 de son \xE2ge, mais peut-\xEAtre en sont-ce des cons\xE9quences, \TeX{} a deux particularit\xE9s qui le rendent peu attractif, voire carr\xE9ment repoussant pour beaucoup de personnes qui s'y essaient.
+
+Tout d'abord, la fa\xE7on intrins\xE8que que \TeX{} a de fonctionner, certes tr\xE8s originale, ne ressemble pas \xE0 celle qui est devenue la norme dans la plupart des langages de programmation. Ceci est \emph{extr\xEAmement} d\xE9routant et conduit bien souvent \xE0 une incompr\xE9hension puis un rejet de ce langage, m\xEAme pour des programmeurs avertis. Car avec \TeX{}, les m\xE9thodes de programmation changent et donc, c'est aussi la fa\xE7on de penser un algorithme qui change !
+
+Pour r\xE9sumer \xE0 l'extr\xEAme, \TeX{} est un langage \emph{de macros}, c'est-\xE0-dire que les appels aux macros provoquent le remplacement de ces macros (et de leurs arguments) par un nouveau code. Ce code --~ou \xAB \idx{texte de remplacement} \xBB~-- est celui qui a \xE9t\xE9 donn\xE9 \xE0 la macro lors de sa d\xE9finition. De plus, et c'est une originalit\xE9 suppl\xE9mentaire en \TeX, lorsqu'on d\xE9finit une macro, non seulement on d\xE9finit son texte de remplacement, mais on d\xE9finit \emph{aussi} la syntaxe avec laquelle elle devra \xEAtre appel\xE9e. Enfin, et c'est l\xE0 un des points les plus difficiles, \TeX{} ne proc\xE8de \xE0 \emph{aucune \xE9valuation}, ni du \idx{texte de remplacement} lors de la d\xE9finition d'une macro, ni des arguments qui lui sont donn\xE9s lorsqu'elle est appel\xE9e.
+
+Voici un exemple qui peut illustrer cette absence d'\xE9valuation. Pour comprendre le probl\xE8me, tenons-nous \xE0 l'\xE9cart de la syntaxe de \TeX{} o\xF9 les commandes doivent commencer par \xAB\verb|\|\xBB et les arguments doivent \xEAtre entre accolades. Adoptons plut\xF4t une syntaxe \xABg\xE9n\xE9rique\xBB o\xF9 les commandes sont \xE9crites normalement et o\xF9 les arguments se trouvent entre parenth\xE8ses. Imaginons qu'une macro \xAB\verb|left|\xBB ait \xE9t\xE9 cr\xE9\xE9e et qu'elle admette deux arguments. Le premier de type chaine de caract\xE8res alphanum\xE9riques, not\xE9 \xAB\verb|A|\xBB et le second de type entier, not\xE9 \xAB\verb|i|\xBB : le r\xE9sultat de cette macro est constitu\xE9 par ce qui se trouve \xE0 gauche du caract\xE8re \no\verb|i| de la chaine \verb|A|. Par exemple, le code :
+
+\centrecode-left(bonjour)(4)-
+
+\noindent donnerait les caract\xE8res se trouvant \xE0 gauche de 4\ieme{} lettre, c'est-\xE0-dire \xAB\verb|bon|\xBB.
+
+De la m\xEAme fa\xE7on, admettons qu'il existe aussi une macro \xAB\verb|right|\xBB qui elle, renvoie ce qui se trouve \xE0 droite du caract\xE8re \no\verb|i| dans la chaine \verb|A|. Et donc :
+
+\centrecode-right(bonjour)(4)-
+
+\noindent donnerait les caract\xE8res \xAB\verb|our|\xBB.
+
+Voici maintenant un raisonnement extr\xEAmement r\xE9pandu en programmation et c'est d'ailleurs le c\oe ur du probl\xE8me. N'importe quel programmeur pense --~avec raison~-- que pour isoler ce qui se trouve entre les caract\xE8res \no2 et \no5 dans la chaine \xAB\verb|bonjour|\xBB (c'est-\xE0-dire les caract\xE8res \xAB\verb|nj|\xBB), il suffit d'\xE9crire :
+
+\centrecode|right(left(bonjour)(5))(2)|
+
+Ce raisonnement suppose que les arguments de \verb|right|--~ici en particulier le premier~-- ont
+ \xE9t\xE9 \xE9valu\xE9s \emph{avant} que la macro n'entre en jeu. Ce premier argument qui est \xAB\verb|left(bonjour)(5)|\xBB serait donc remplac\xE9 par son r\xE9sultat \xAB\verb|bonj|\xBB et finalement, apr\xE8s cette \xE9valuation, tout se passe comme si on avait l'appel :
+
+\centrecode|right(bonj)(2)|
+
+\noindent Or, cette \xE9valuation n'a pas lieu avec \TeX{} ! Essayons de nouveau d'appr\xE9hender ce code, mais adoptons un esprit \TeX ien :
+
+\centrecode|right(left(bonjour)(5))(2)|
+
+\noindent \TeX{} ex\xE9cute le code de gauche \xE0 droite donc, lorsqu'il ex\xE9cute la macro \verb|right|, il va lui transmettre ses deux arguments qui sont \xAB\verb|left(bonjour)(5)|\xBB et \xAB\verb|2|\xBB. Et donc, les caract\xE8res renvoy\xE9s seront tout ce qui se trouve \xE0 droite de la 2\ieme{} lettre du premier argument, c'est-\xE0-dire \xAB\verb|ft(bonjour)(5)|\xBB.
+
+Le simple fait que le premier argument ne soit pas \xE9valu\xE9 conduit non seulement \xE0 un r\xE9sultat radicalement diff\xE9rent, mais surtout implique que si l'on souhaite un comportement \xABnormal\xBB, c'est au programmeur d'int\xE9grer \xE0 la macro un m\xE9canisme qui se charge d'\xE9valuer cet argument avant que le code utile de la macro ne traite le r\xE9sultat. Pour ceux qui viennent d'autres langages, cette charge de travail suppl\xE9mentaire est souvent ressentie comme une corv\xE9e, sans compter que le code s'en trouve alourdi et donc moins lisible.
+
+Une bonne partie des probl\xE8mes que rencontrent les personnes non habitu\xE9es \xE0 \TeX{} vient de la confusion qu'ils font entre :
+\begin{itemize}
+	\item l'affichage qui r\xE9sulte d'un code;
+	\item ce code lorsqu'il est dans l'argument d'une macro.
+\end{itemize}
+
+L'explication de cette confusion tient au fait que la plupart des langages ont un m\xE9canisme --~appel\xE9 \xAB\idx{pr\xE9processeur}\xBB~-- qui \emph{lit, analyse, \xE9value puis remplace les arguments par leurs r\xE9sultats}, et ce avant que la macro ne soit ex\xE9cut\xE9e. Avec \TeX{}, ce pr\xE9processeur est r\xE9duit \xE0 sa plus simple expression : il ne fait que \emph{lire} et \emph{tokenizer} cet argument\footnote{Dans ce cas, on a affaire \xE0 un pr\xE9processeur de bas niveau, le plus bas qui soit, et on parle de \xABpr\xE9processeur lexical\xBB.}.
+
+\Qu elle que soit l'affinit\xE9 --~ou l'adoration~-- que l'on \xE9prouve envers \TeX{}, on est bien oblig\xE9 de reconnaitre que cette fa\xE7on de faire n'est pas \emph{naturelle}. Car notre cerveau est lui aussi dot\xE9 d'un \idx{pr\xE9processeur} intelligent qui agit de fa\xE7on semblable \xE0 celui des langages de programmation \xABnormaux\xBB. Par exemple, n'apprend-on pas en math\xE9matiques que :
+
+\[\text{si }f(x)=x^2\text{\quad alors\quad}f(2\times3-1)=25\]
+
+\noindent Avant tout calcul concernant la fonction $f$, ne proc\xE8de-t-on pas spontan\xE9ment \xE0 l'\xE9valuation de l'argument \xAB$2\times3-1$\xBB pour le remplacer par le r\xE9sultat, c'est-\xE0-dire le nombre $5$ ? Ce faisant, ne proc\xE8de-t-on pas comme les langages de programmation modernes qui, eux aussi, \xE9valuent les arguments des macros ?
+
+Tout ceci conduit donc \xE0 une premi\xE8re r\xE8gle, probablement une des plus importantes de toutes :
+
+\label{regle.argument}\begin{regle}
+Si un code quelconque, notons-le \hbox{\verb|<|$x$\verb|>|}, produit un affichage \hbox{\verb|<|$y$\verb|>|} alors, sauf cas tr\xE8s particulier, il n'est pas \xE9quivalent d'\xE9crire \hbox{\verb|<|$x$\verb|>|} ou \hbox{\verb|<|$y$\verb|>|} dans l'argument d'une macro.
+\end{regle}
+\grandsaut
+
+L'autre inconv\xE9nient de \TeX{} qui rebute les personnes habitu\xE9es \xE0 des langages plus modernes est que, pris comme un langage de programmation, \TeX{} est dot\xE9 du \emph{strict minimum} ! Pour parler avec mod\xE9ration, l'\emph{extr\xEAme minimalisme}\footnote{D'autres, moins bienveillants, parleraient de \xABpauvret\xE9\xBB.} de ce langage est totalement d\xE9routant, car toutes les facilit\xE9s auxquelles les langages modernes nous ont habitu\xE9es depuis longtemps ne sont tout simplement pas impl\xE9ment\xE9es dans \TeX{}. On ne parle pas ici de structures \xE9volu\xE9es comme de pointeurs ou pire, de programmation orient\xE9e objet. Non, on parle de structures de contr\xF4le des plus \emph{basiques}. Il va falloir renoncer \xE0 la cr\xE9ation de variables typ\xE9es, aux op\xE9rateurs logiques bien pratiques lors des tests (\xAB\texttt{or}\xBB, \xAB\texttt{and}\xBB, \xAB\texttt{not}\xBB), aux boucles (\xAB\texttt{for}\xBB, \xAB\texttt{while}\xBB, etc.), aux tableaux, aux nombres d\xE9cimaux et aux op\xE9rations scientifiques, ainsi qu'\xE0 beaucoup d'autres choses. En \TeX{}, on doit se contenter de r\xE9cursivit\xE9, de tests simples, de nombres entiers et des quatre op\xE9rations arithm\xE9tiques, et encore avec quelques limitations pour ces derni\xE8res. Et si l'on veut profiter de structures plus \xE9volu\xE9es, il faut les programmer soi-m\xEAme ! Heureusement, cela est toujours possible, car \TeX{}, dans son minimalisme, a \xE9t\xE9 dot\xE9 de tout ce qu'il faut pour construire n'importe quel algorithme, aussi complexe soit-il. On qualifie un tel langage de \xABcomplet\xBB. On aborde d'ailleurs dans ce livre la programmation de structures de contr\xF4le plus \xE9volu\xE9es que celles directement accessibles par \TeX.
+
+\xC9videmment, lorsqu'on programme en \TeX{}, on ne se trouve pas au niveau de l'assembleur\footnote{Le \xABlangage machine\xBB est le langage de plus bas niveau qui soit, c'est-\xE0-dire le moins compr\xE9hensible par un humain : ce sont des commandes directement compr\xE9hensibles par le microprocesseur qui sont des assemblages de bits ou si l'on pr\xE9f\xE8re, des suites de 0 et de 1.
+
+Ces suites de bits, traduites en instructions ais\xE9ment m\xE9morisables par un humain, constituent le langage \xABassembleur\xBB.} car tout de m\xEAme, \TeX{} est un langage de bien plus haut niveau. En revanche, ce qui est certain, c'est qu'on programme \xE0 un niveau beaucoup plus bas que celui de tous les langages actuels. Cela oblige donc \xE0 revenir aux fondamentaux de la programmation, et ce retour aux sources est parfois v\xE9cu comme une r\xE9gression par les personnes venant d'autres langages. Pourtant, contrairement \xE0 ce que l'on peut penser, revenir aux concepts de base de la programmation aide \xE0 \xE9laborer des algorithmes plus efficaces et mieux construits (ceci \xE9tant vrai quel que soit le langage utilis\xE9), oblige \xE0 mieux comprendre les m\xE9thodes sous-jacentes aux structures complexes et en fin de compte, fait accomplir des progr\xE8s en algorithmique tout comme en compr\xE9hension de la fa\xE7on dont fonctionne un ordinateur.
+
+\section{La rel\xE8ve}
+Ces contraintes intrins\xE8ques \xE0 \TeX{} font que, petit \xE0 petit, de plus en plus de gens gravitant autour de la sph\xE8re \TeX{} --~des utilisateurs de \LaTeX{} pour la plupart~-- ont admis que ce langage \xE9tait devenu obsol\xE8te, tant pour la composition que pour la programmation. \xC0 leurs yeux, il devenait convenable, sinon de le cacher aux yeux des utilisateurs, au moins de proposer des alternatives consid\xE9r\xE9es comme viables.
+
+Le probl\xE8me est que le \idx[!\LaTeX]{format} \texttt{latex} offre une collection de macros pr\xE9compil\xE9es appel\xE9es \LaTeX{} dont le but est de proposer des commandes de haut niveau pour la composition mais h\xE9las, \emph{presque rien} pour la programmation ! Pour pallier ce manque, les utilisateurs de \LaTeX{} se sont vus proposer des extensions sp\xE9cialis\xE9es qui rendent la vie du programmeur plus simple et qui mettent \xE0 disposition des commandes permettant de cr\xE9er facilement des boucles ou autres structures de contr\xF4le de plus haut niveau.
+
+Le progr\xE8s que cela repr\xE9sente est consid\xE9rable, car la facilit\xE9 d'utilisation est au rendez-vous. Il devient ainsi \emph{tr\xE8s} facile de faire appel \xE0 une boucle de type \xAB\verb|for|\xBB. Bien s\xFBr, chaque \idx{package} a sa propre syntaxe et ses propres instructions. Mais finalement, beaucoup d'entre eux ont une intersection non vide qui est la mise \xE0 disposition de commandes sur les boucles et les tests notamment. \xC9tant donn\xE9 le grand nombre de packages disponibles pour la seule programmation, il est presque impossible de connaitre les instructions de tous les packages. Le travers que cela cr\xE9\xE9 est que certains utilisateurs deviennent totalement d\xE9pendants d'un package auquel ils sont habitu\xE9s, quitte \xE0 ce que cela confine parfois \xE0 l'absurde. Un des exemples les plus frappants est le package \xABti\textit kz\xBB dont le but est de proposer des commandes de tr\xE8s haut niveau pour faire des dessins vectoriels. C'est un package d'une taille absolument gigantesque qui compte \xE0 peu pr\xE8s \numprint{300000}\footnote{\xC0 comparer avec les \numprint{8000} lignes du code de \LaTeX{} !} lignes de code, \xE9crit en \TeX{} et en perp\xE9tuelle \xE9volution et qui propose, en plus de commandes de dessin vectoriel, des outils qui facilitent la vie en programmation. Bien entendu, on y trouve des commandes qui permettent de construire des boucles. L'absurde de la situation est que parfois, certains utilisateurs d\xE9pendants de ti\textit kz et incapables de programmer par ignorance des commandes de \TeX{}, en viennent \xE0 charger un \idx{package} aussi volumineux pour ne se servir que d'une instruction en vue de cr\xE9er une boucle, le tout en dehors de tout contexte de dessin. Certes, la solution fonctionne, mais l'efficacit\xE9 n'est pas vraiment optimale.
+\grandsaut
+
+Le projet qui est actuellement en pleine phase d'exp\xE9rimentation est \LaTeX3\index{format!\LaTeX3|(}. Il s'agit d'un projet qui rel\xE8ve un d\xE9fi tr\xE8s ambitieux, celui de remplacer et d'am\xE9liorer l'actuelle version de \LaTeX. Ce projet, en maturation intense depuis de nombreuses ann\xE9es et anim\xE9 par une \xE9quipe de codeurs tr\xE8s exp\xE9riment\xE9s, arrive actuellement \xE0 un stade o\xF9 des pans entiers, bien que toujours en \xE9volution, deviennent utilisables. Le pan qui \xE9merge en ce moment est carr\xE9ment un nouveau langage de programmation enti\xE8rement \xE9crit en \TeX{} ! Comme \TeX{} est un langage complet, tout est possible, m\xEAme le plus inattendu ! Ce nouveau langage de programmation offre d'innombrables possibilit\xE9s que \TeX{} ne proposait pas, certaines extr\xEAmement ardues \xE0 programmer. De plus, les auteurs ont essay\xE9 autant qu'ils le pouvaient d'inclure un \idx{pr\xE9processeur}, actionnable \xE0 volont\xE9 et agissant sur les arguments des macros individuellement. Un code \xE9crit dans ce nouveau langage devient donc beaucoup plus \xE9pur\xE9 et lisible que du code \TeX{}, autant par la pr\xE9sence de ce \idx{pr\xE9processeur} que par l'extraordinaire diversit\xE9 des macros mises \xE0 disposition. Celles-ci couvrent des domaines aussi vari\xE9s que :
+
+\begin{itemize}
+	\item toutes les structures de contr\xF4le basiques : tests, boucles;
+	\item nombres d\xE9cimaux en virgule fixe ou flottante et les op\xE9rations arithm\xE9tiques et scientifiques sur ces nombres ;
+	\item recherche, remplacement dans une chaine de caract\xE8res avec la possibilit\xE9 de faire appel \xE0 des crit\xE8res dont la syntaxe est proche de celle des \xABexpressions r\xE9guli\xE8res\footnote{Une expression r\xE9guli\xE8re est une suite de signes, appel\xE9s \xABmotif\xBB, qui d\xE9crit selon une syntaxe pr\xE9cise des r\xE8gles auxquelles doit satisfaire une chaine de caract\xE8re lors d'une recherche.
+
+	Un livre entier serait \xE0 peine suffisant pour explorer le monde des expressions r\xE9guli\xE8res. Ce qu'il faut savoir est qu'elles sont tr\xE8s largement utilis\xE9es autant pour leur compacit\xE9 que pour leur puissance.}\xBB;
+	\item tri de donn\xE9es ;
+	\item etc.
+\end{itemize}
+
+Le revers de la m\xE9daille est qu'il faut apprendre ce nouveau langage dont la syntaxe est suffisamment \xE9loign\xE9e de celle de \TeX{} pour d\xE9router, voire rebuter un grand nombre d'utilisateurs habitu\xE9s depuis des ann\xE9es voire des d\xE9cennies \xE0 celle de \TeX{} ou \LaTeX. Ce nouveau langage se veut en effet beaucoup plus r\xE9gulier que ne l'est \TeX, \xE0 tel point qu'il peut apparaitre fade, aseptis\xE9 et domestiqu\xE9 en regard de l'original qui, par ses d\xE9fauts un peu folkloriques, peut \xEAtre ressenti comme davantage original et attachant. Le point le plus discutable est que \TeX{}, le langage sous-jacent, est volontairement rendu totalement invisible pour l'utilisateur final de \LaTeX3, toujours selon la volont\xE9 que \TeX{} doit \xEAtre cach\xE9 \xE0 l'utilisateur, car jug\xE9 trop difficile, obsol\xE8te et contraignant. \LaTeX3 cr\xE9\xE9 finalement une dichotomie entre les utilisateurs. Les uns, pragmatiques, d\xE9sireux de savoir et pr\xEAts \xE0 apprendre un nouveau langage, se moquent \xE9perdument du \emph{vrai} langage qui se trouve sous cette \xABcouche\xBB, trop contents d'avoir enfin \xE0 leur disposition un langage au comportement quasi \xABnormal\xBB. Les autres, par curiosit\xE9 intellectuelle et par d\xE9sir de comprendre, ou tout simplement par rejet de \LaTeX3, n'y adh\xE8reront pas et pr\xE9f\xE8reront ouvrir le capot afin de voir ce qui se joue en coulisses.
+
+Il va sans dire que ces derniers devront, si ce n'est d\xE9j\xE0 fait, se mettre \xE0 \TeX{} et que les autres doivent sans tarder lire la documentation de \LaTeX3\index{format!\LaTeX3|)}.
+
+\section{La r\xE9volution}
+Mais que ces utilisateurs ne se ruent pas trop vite sur \LaTeX3, car il y a autre chose. Depuis l'ann\xE9e 2005, un nouveau moteur est en train de voir le jour. Il s'agit de lua\TeX{}\idx*[|(]{moteur!luatex}, un moteur o\xF9 bien s\xFBr le langage \TeX{} est toujours accessible, mais o\xF9 est \xE9galement rendu possible l'acc\xE8s au langage \xAB\texttt{lua}\xBB. Ce langage, cr\xE9\xE9 en 1993 a justement \xE9t\xE9 \xE9crit pour \xEAtre embarqu\xE9 dans des applications pour en \xE9tendre les possibilit\xE9s. Lua\idx*{lua} est un langage \emph{interpr\xE9t\xE9} mais surtout, il poss\xE8de tout ce que \TeX{} n'a pas et donc tout ce que les langages modernes ont! Parmi les fonctionnalit\xE9s les plus essentielles, on peut citer :
+
+\begin{itemize}
+	\item acc\xE8s facile et \xABnaturel\xBB aux structures de contr\xF4le habituelles : boucles (\texttt{repeat}, \texttt{while}, \texttt{for}), tests simples, tests compos\xE9s avec des op\xE9rateurs logiques sur les conditions;
+	\item fonctions dont les arguments sont \xE9valu\xE9s par un \idx{pr\xE9processeur};
+	\item nombres, qui sont d'un seul type, les d\xE9cimaux \xE0 virgule flottante. Ceux-ci sont assortis des op\xE9rations arithm\xE9tiques et d'une biblioth\xE8que de fonctions math\xE9matiques;
+	\item variables typ\xE9es (chaines de caract\xE8res, bool\xE9ens, tables);
+	\item acc\xE8s aux fonctions du syst\xE8me (acc\xE8s aux entr\xE9es/sorties, aux fonctions de date, d'heure);
+	\item etc.
+\end{itemize}
+
+L'acc\xE8s \xE0 \texttt{lua} peut donc grandement faciliter la vie d'un programmeur pour \xE9crire des algorithmes qui autrement, seraient difficiles \xE0 coder en \TeX. Cela ne doit tout de m\xEAme pas faire oublier que certains algorithmes \emph{doivent} \xEAtre cod\xE9s en \TeX, car c'est le langage qui a le dernier mot en mati\xE8re de composition.
+
+Mais il y a bien plus important. Le plus \xE9tonnant est que \texttt{lua} permet aussi l'acc\xE8s aux m\xE9canismes les plus intimes de \TeX{}. Les auteurs ont r\xE9ussi le tour de force d'impl\xE9menter \texttt{lua} \xE0 un niveau tellement bas qu'il est possible d'agir sur le programme \texttt{tex} lui-m\xEAme et d'acc\xE9der \xE0 des endroits auparavant inaccessibles et non modifiables (on dit qu'ils sont cod\xE9s \xABen dur\xBB). Cet acc\xE8s ouvre des possibilit\xE9s inou\xEFes, car lors de la compilation et par l'interm\xE9diaire de \texttt{lua}, il devient possible de modifier ou contr\xF4ler des comportements tr\xE8s fins de \TeX, le rendant extr\xEAmement configurable, bien plus qu'il ne l'\xE9tait. Il devient possible, par exemple, d'effectuer ces actions qui \xE9taient impossibles avant :
+
+\begin{itemize}
+	\item relever les positions de toutes les espaces inter-mots d'un paragraphe afin de v\xE9rifier que certaines d'entre elles, au-del\xE0 d'un certain nombre, ne soient pas adjacentes et align\xE9es verticalement, cr\xE9ant ainsi ce que l'on appelle en typographie des \xABrivi\xE8res\xBB ;
+	\item lors de l'affichage, remplacer chaque occurrence d'un groupe de caract\xE8res par un autre, par exemple, tous les \xABonsieur\xBB par \xABadame\xBB;
+	\item etc.
+\end{itemize}\idx*[|)]{moteur!luatex}
+
+\section{Et le bon dans tout \xE7a?}
+Bien \xE9videmment, de \TeX{}, \LaTeX3 et lua\TeX, aucun n'est le bon, la brute ou le truand ! Chacun a ses propres caract\xE9ristiques et chacun cohabite avec les deux autres sans qu'aucun ne soit en comp\xE9tition avec un autre. Au contraire, il faut se r\xE9jouir puisque le monde de \TeX{}, d\xE9j\xE0 d'une extr\xEAme complexit\xE9, mais presque fig\xE9 depuis 1982 est en pleine effervescence et promet maintenant de fa\xE7on certaine que des choses impossibles auparavant ne le seront plus. L'avenir s'ouvre riche en perspectives et sans r\xEAver, ne peut-on pas imaginer, d'ici quelques ann\xE9es, un \idx{format} bas\xE9 sur le moteur lua\TeX{}\idx*{moteur!luatex} contenant les macros pr\xE9compil\xE9es de \LaTeX3, le tout formant une unit\xE9 r\xE9unissant les trois protagonistes qui sera d'une puissance et d'une souplesse jusqu'alors inconnues ? Peut-on d\xE9j\xE0 mesurer l'immense bond en avant que constituera cette symbiose ? Et que feront les packages de cette nouvelle \xE8re s'ils savent exploiter les trois langages, quels miracles seront-ils capables de r\xE9aliser ?
+
+\chapter{Avant de commencer}
+\section{La programmation \TeX{} oui, mais pour qui ?}
+Finalement, \xE0 qui s'adresse ce livre ?
+\grandsaut
+
+Tout d'abord aux utilisateurs de plain-\TeX, \LaTeX{} ou d'un autre \idx{format} qui souhaitent acqu\xE9rir un peu d'autonomie dans la programmation en \TeX. Car un jour ou l'autre c'est in\xE9vitable, on en a besoin, ne serait-ce que parce que les packages disponibles n'ont pas ne couvrent pas tous les cas ou parce qu'on ignore qu'un package r\xE9pondant \xE0 un besoin pr\xE9cis existe. \Qu 'y a-t-il de plus frustrant que de renoncer en se sachant incapable d'\xE9crire le moindre code non lin\xE9aire, surtout lorsqu'on en a un urgent besoin ? \Qu elle satisfaction intellectuelle retire-t-on lorsqu'au moindre probl\xE8me urgent et incontournable, on est contraint de poser une question de programmation \TeX{} sur un forum sp\xE9cialis\xE9 ? Est-ce vraiment valorisant d'attendre une r\xE9ponse, \xAB copier-coller \xBB le code donn\xE9 par un connaisseur sans en comprendre le fonctionnement et se dire qu'au prochain probl\xE8me, il faudra poser une question \xE0 nouveau ?
+
+Ce livre s'adresse aussi aux curieux, \xE0 ceux d\xE9sireux d'apprendre, ceux qui souhaitent soulever un coin du voile. En effet, \TeX{} est r\xE9put\xE9 comme \xE9tant un langage r\xE9serv\xE9 \xE0 quelques \xABiniti\xE9s\xBB, voire carr\xE9ment inaccessible si l'on n'est pas \xAB\TeX-compatible\xBB. La lecture de ce livre dissipera un peu l'aura quasi mystique qui l'enveloppe --~c'est en tout cas un des buts recherch\xE9s~--, assouvissant les l\xE9gitimes interrogations que se posent les \xABnon-initi\xE9s\xBB \xE0 son sujet.
+
+Il s'agit aussi de faire red\xE9couvrir qu'il existe d'autres voies en programmation et celle que prend \TeX{} est des plus originales. Car finalement, tous les \xABpoids lourds\xBB des langages modernes ne tendent-ils pas \xE0 se ressembler tous ? Ne proposent-ils pas un peu tous les m\xEAmes fonctionnalit\xE9s, au moins jusqu'\xE0 un certain niveau ? Il est assez excitant de d\xE9couvrir un langage de macros tellement ceux-ci sont rares\footnote{Le langage \xAB \texttt{M4} \xBB est \xE9galement un langage de macros.}. L'apprentissage d'un tel langage est excitant d'abord parce que cela \xE9tend la culture informatique, mais surtout parce cela ouvre de nouvelles voies en programmation en suscitant des m\xE9thodes de programmation nouvelles. Il est d'ailleurs reconnu que les langages de macros sont puissants, m\xEAme s'ils proc\xE8dent \xE0 des remplacements \emph{aveugles} de macros par leur \idx{texte de remplacement}. Ce manque d'\xE9valuation se paie par des erreurs parfois difficiles \xE0 corriger, car surgissant \xE0 des moments ou \xE0 des endroits tr\xE8s \xE9loign\xE9s de l'origine du probl\xE8me.
+\grandsaut
+
+Bien s\xFBr, nulle part nous n'apprendrons \xE0 programmer des macros aussi complexes que celles de \LaTeX3, nous resterons beaucoup plus modestes. Le but de ce livre est de donner les cl\xE9s pour comprendre \emph{comment} il faut s'y prendre. La compr\xE9hension de quelques concepts doit pousser, au fur et \xE0 mesure de la lecture, \xE0 coder soi-m\xEAme et essayer de voler de ses propres ailes. Il est en effet primordial, quel que soit le niveau atteint, de toujours exp\xE9rimenter par soi-m\xEAme, car se contenter d'une lecture lin\xE9aire ne peut suffire. Imaginerait-on qu'un joueur d\xE9butant de bridge, jeu complexe s'il en est, deviendrait subitement un bon joueur apr\xE8s avoir simplement lu d'un trait un ouvrage sur le sujet ? La r\xE9ponse est \xE9videmment n\xE9gative, car tester, modifier, adapter, exp\xE9rimenter, se \xAB planter \xBB, apprendre de ses erreurs, recommencer, recommencer encore fait partie de tout apprentissage. Cela est valable dans tous les domaines, et en programmation --~surtout en \TeX~-- peut-\xEAtre encore davantage !
+\section{Ce qu'il faut savoir}
+Il ne serait pas raisonnable d'aborder le c\xF4t\xE9 langage de \emph{programmation} de \TeX{} sans avoir jamais pratiqu\xE9 \TeX{}, \LaTeX{} ou un autre \idx{format} en tant que langage de \emph{composition}. Non, vraiment pas raisonnable. Cette pratique est indispensable, ne serait-ce que pour s'impr\xE9gner de la syntaxe et se familiariser avec l'outil. Ce livre ne s'adresse donc pas au d\xE9butant de la premi\xE8re heure, sauf inconscient ou masochiste qui souhaiterait se d\xE9gouter \xE0 tout jamais de \TeX{} !
+
+Mais tout compte fait et nous allons le voir ci-dessous, les choses \xE0 savoir ne sont pas l\xE9gion.
+
+\subsection{\TeX{} et la composition}
+Il faut avoir une petite id\xE9e de la fa\xE7on dont \TeX{} compose du texte. Le sch\xE9ma mental le plus proche de la r\xE9alit\xE9 est de se dire que \TeX{} fonctionne par placement de boites sur la page. La g\xE9om\xE9trie des boites de \TeX{} est assez facile \xE0 comprendre. Voici la lettre \xABg\xBB, \xE9crite en tr\xE8s grand et dont on a trac\xE9 les contours de la \emph{boite englobante}\idx*{boite!englobante} qui traduit les dimensions avec lesquelles \TeX{} voit une boite :
+
+\begin{centrage}
+\dimenbox[75]{g}\global\setbox\testbox\hbox{\unhbox\testbox}
+\end{centrage}
+
+Comme on peut le voir, la boite englobante\idx*{boite!englobante} a trois dimensions\idx*{boite!dimension}\idx*{boite!g\xE9om\xE9trie}, tout comme n'importe quelle boite dans le monde de \TeX{}\idx*{boite!g\xE9om\xE9trie} :%
+\begin{itemize}
+	\item une largeur qui est ici de \the\wd\testbox;
+	\item une hauteur, de \the\ht\testbox
+	\item une profondeur \xE9gale \xE0 \the\dp\testbox
+\end{itemize}
+
+\TeX{} exprime naturellement les dimensions en \emph{points}\idx*{pt (unit\xE9)}\idx*{unit\xE9!pt} (mais nous le verrons, il y a bien d'autres unit\xE9s possibles), et un centim\xE8tre\idx*{unit\xE9!cm}\idx*{cm (unit\xE9)} contient exactement \texttt{\the\dimexpr1cm\relax}.
+
+La hauteur et la profondeur s'\xE9tendent verticalement de part et d'autre de la \emph{\idx{ligne de base}}. C'est une ligne horizontale th\xE9orique autour de laquelle s'organise la g\xE9om\xE9trie d'une boite. Pour les boites contenant les caract\xE8res, sa position pratique co\xEFncide avec le bas des caract\xE8res sans jambage comme \xABa,\xBB, \xABb\xBB, \xABc\xBB, etc.\medbreak
+
+{%
+\noindent\setbox0\hbox{\Large Programmer en \TeX{} est \emph{facile}.}%
+\hfill
+\rlap{\kern-1cm\vrule height0.2pt depth0.2pt width\dimexpr\wd0+2cm}%
+\box0
+\hfill\null
+}%
+\medbreak
+
+Chaque boite a un point particulier, appel\xE9 \emph{\idx{point de r\xE9f\xE9rence}} situ\xE9 sur la fronti\xE8re gauche de la \idx*{boite!englobante}boite englobante. Ce point de r\xE9f\xE9rence est, dans la boite contenant \xABg\xBB, repr\xE9sent\xE9 par un point \xAB\tikz\draw[fill,black](0.35pt,0pt)circle(1pt);\xBB. Les boites sont donc correctement plac\xE9es verticalement parce que leur point de r\xE9f\xE9rence vient sur la \idx{ligne de base} de la ligne courante, et sont positionn\xE9es les unes \xE0 la suite des autres parce que le \idx{point de r\xE9f\xE9rence} de la boite suivante est situ\xE9 sur la fronti\xE8re droite de la boite pr\xE9c\xE9dente.
+
+\TeX{} proc\xE8de par \xE0-coups, composant tour \xE0 tour des paragraphes\idx*[|(]{paragraphe!composition}. La m\xE9canique fonctionne de cette mani\xE8re : lorsque la commande \idx\par est rencontr\xE9e, le paragraphe qui vient d'\xEAtre lu et qui est jusqu'alors stock\xE9 en m\xE9moire est \xAB compos\xE9 \xBB. C'est le moment o\xF9 \TeX{} appr\xE9hende le paragraphe dans sa totalit\xE9 pour d\xE9cider o\xF9 se feront les coupures de ligne. Chaque ligne de texte est ainsi constitu\xE9e
+
+\begin{itemize}
+	\item de boites contenant les caract\xE8res\footnote{Pour \xEAtre clair, \TeX{} ne connait \xE0 aucun moment le dessin de chaque caract\xE8re. Il ne connait que les dimensions de la boite qui le contient, qui est la boite englobante.}. Dans un mot, chaque boite est adjacente \xE0 la pr\xE9c\xE9dente;
+	\item d'espaces qui peuvent, dans une certaine mesure, s'\xE9tirer ou se comprimer de telle sorte que la largeur de la ligne soit exactement celle de la largeur du paragraphe. La derni\xE8re ligne du paragraphe, moins large que ne l'est le paragraphe, a des espaces qui ont leur largeur naturelle.
+\end{itemize}
+
+Pendant tout le paragraphe, \TeX{} positionne cette \emph{liste} d'\xE9l\xE9ments \xE0 la suite les uns des autres de fa\xE7on horizontale pour former chaque ligne : on dit qu'il fonctionne en \xABmode horizontal\idx*{mode!horizontal}\xBB. Ce mode est d'ailleurs celui dans lequel il se trouve pour la plupart du temps lorsqu'il compose du texte.
+
+La composition proprement dite du paragraphe enferme chaque ligne dans une boite et les boites contenant les lignes sont positionn\xE9es \emph{verticalement} les unes sous les autres, chacune \xE9tant s\xE9par\xE9e de sa voisine par un \xAB \idx{ressort d'interligne} \xBB (page~\pageref{ressort.interligne}).
+
+\begingroup
+\clubpenalty=0 % pas de p\xE9nalit\xE9 suppl\xE9mentaire apr\xE8s la premi\xE8re ligne
+\interlinepenalty=0 % pas de p\xE9nalit\xE9 inter-ligne
+\widowpenalty=0 % pas de p\xE9nalit\xE9 suppl\xE9mentaire avant la derni\xE8re ligne
+\leftline{}
+\let\formatline\frbox
+\frboxrule=0.3pt
+\frboxsep=-\frboxrule% encadrer vers "l'int\xE9rieur"
+\numlines
+On peut observer ce \idx{ressort d'interligne} dans ce paragraphe o\xF9 la boite englobante\idx*{boite!englobante} de chaque ligne est trac\xE9e. On peut constater que la boite englobante d'une ligne ne touche pas celle de ses voisines : l'espace vertical qui les s\xE9pare est l'espace interligne. Si cet espace \xE9tait nul, les lignes seraient beaucoup trop serr\xE9es et cela rendrait la lecture tr\xE8s p\xE9nible.
+\endnumlines
+\endgroup
+
+Apr\xE8s avoir form\xE9 le paragraphe (et donc apr\xE8s avoir ex\xE9cut\xE9 la commande \idx\par), le mode\idx*{mode!vertical} vertical est en vigueur, puisque \TeX{} vient de placer les lignes du paragraphe pr\xE9c\xE9dent verticalement : il est donc pr\xEAt \xE0 positionner d'autres \xE9l\xE9ments verticalement les uns sous les autres. Bien \xE9videmment, si un nouveau paragraphe commence juste apr\xE8s, \TeX{} repasse en mode horizontal\idx*{mode!horizontal} d\xE8s le premier caract\xE8re rencontr\xE9.
+
+Au fur et \xE0 mesure que les lignes et autres objets remplissent verticalement la page, il arrive un moment o\xF9 un certain seuil de remplissage est atteint et \TeX{} d\xE9cide o\xF9 se situe la coupure de page.  La page destin\xE9e \xE0 \xEAtre compos\xE9e est \xE0 ce moment enferm\xE9e dans une ultime boite. Cette boite signe la fin de l'imbrication des boites en poup\xE9es gigognes et est envoy\xE9e vers le fichier de sortie.\idx*[|)]{paragraphe!composition}%
+
+\subsection{\Qu elques commandes utiles}
+\subsubsection{\texttt{\textbackslash par} et les changements de mode}
+La plus courante de toutes les primitives est sans doute \idx\par puisque sans elle, il n'y aurait pas de \idx{paragraphe} et donc pas de typographie. Ajoutons \xE0 ce qui a \xE9t\xE9 dit ci-dessus la r\xE8gle suivante :
+
+\label{par.consecutifs}\begin{regle}
+Lorsque \TeX{} est en mode vertical\idx*{mode!vertical}, la commande \idx[!mode vertical]\par\idx*{mode!vertical} est sans effet.
+
+Par cons\xE9quent, si l'on se trouve en mode horizontal\idx*{mode!horizontal} et si plusieurs commandes \idx[!cons\xE9cutifs]\par se suivent, seule la premi\xE8re est utilis\xE9e pour composer le paragraphe en cours et les autres sont ignor\xE9es.
+\end{regle}
+
+On peut quitter le mode vertical\idx*{mode!vertical} sans afficher aucun caract\xE8re avec la macro de plain-\TeX{} \idx\leavevmode.
+
+D'autres primitives commandent \xE0 \TeX{} le passage en mode horizontal\idx*{mode!horizontal}, mais font aussi autre chose :
+\begin{itemize}
+	\item \idx\indent ins\xE8re au d\xE9but de la liste horizontale une espace de valeur \idx\parindent, qui est la primitive contenant la dimension du retrait de la premi\xE8re ligne d'un paragraphe (plain-\TeX{} initialise cette dimension \xE0 \texttt{20pt} en proc\xE9dant \xE0 l'assignation \xAB\verb*|\parindent=20pt |\xBB);
+	\item \idx\noindent demande \xE0 ce que le prochain paragraphe\idx*{paragraphe!indentation} ne soit pas indent\xE9, c'est-\xE0-dire que sa premi\xE8re ligne ne commence pas en retrait.
+\end{itemize}
+
+\subsubsection{Espaces s\xE9cables et ins\xE9cables}
+La primitive \idx\kern, suivie d'une dimension, ins\xE8re dans la liste courante une espace ins\xE9cable\idx*{espace!ins\xE9cable} de la dimension voulue. Cette espace est ins\xE9cable, car aucune coupure (de page ou de ligne) ne pourra se faire sur cette espace. Il est important de noter que \idx\kern ob\xE9it au mode en cours; l'espace est horizontale si \TeX{} est en mode horizontal\idx*{mode!horizontal} et sera verticale sinon. Voici ce qu'il se passe si l'on \xE9crit \verb|A\kern 5mm B| :
+
+\begin{centrage}
+	A\kern 5mm B
+\end{centrage}
+
+\noindent L'espace de \texttt{5mm} se trouve entre le bord droit de la boite englobante\idx*{boite!englobante} de \xAB A \xBB et le bord gauche de la boite englobante de \xAB B \xBB.
+
+Pour ins\xE9rer une espace verticale suppl\xE9mentaire de \numprint[mm]5
+ entre deux lignes, il suffit de passer en mode vertical\idx*{mode!vertical} avec \idx\par pour que \idx\kern agisse dans ce mode. Ainsi, \verb|A\par\kern 5mm B| se traduit par :
+
+\begin{centrage}
+	A\par\kern 5mm B
+\end{centrage}
+\grandsaut
+
+L'espace entre le bas de la lettre \xABA\xBB et le haut de la lettre \xABB\xBB est l\xE9g\xE8rement sup\xE9rieure \xE0 \numprint[mm]5 car le \idx{ressort d'interligne} s'ajoute \xE0 l'espace sp\xE9cifi\xE9e par \idx\kern.\grandsaut
+
+Si l'on veut ins\xE9rer des espaces \emph{s\xE9cables}\idx*{espace!s\xE9cable}, c'est-\xE0-dire susceptibles d'\xEAtre \emph{remplac\xE9es}\footnote{Il faut bien lire \xAB remplac\xE9es \xBB, car une espace s\xE9cable est supprim\xE9e si elle se trouve \xE0 un endroit de coupure. Les espaces s\xE9cables les plus courantes sont les espaces tap\xE9s dans le code pour s\xE9parer les mots.} par une coupure de ligne ou de page, il faut utiliser soit \idx\hskip, soit \idx\vskip. La premi\xE8re lettre d\xE9signant le mode dans lequel on veut que cette espace soit ins\xE9r\xE9e et commandant le passage dans ce mode. Ces deux primitives doivent \xEAtre suivies d'une dimension de ressort (voir page~\pageref{dimension.ressort}). Plain-\TeX{} met \xE0 disposition deux macros \idx\quad et \idx\qquad ins\xE9rant respectivement une espace horizontale s\xE9cable\idx*{espace!s\xE9cable} de \verb|1em| et de \verb|2em|. L'unit\xE9 \verb|em|\idx*{unit\xE9!em} d\xE9pend du contexte : c'est la dimension horizontale de la boite englobante\idx*{boite!englobante} de lettre \xAB\verb|m|\xBB, compos\xE9e dans la fonte en cours.
+
+La macro \idx\smallskip ins\xE8re verticalement \xE0 l'aide de \idx\vskip l'espace \xE9lastique stock\xE9e dans le registre \idx\smallskipamount et qui vaut dans plain-\TeX{} \xAB\texttt{3pt plus 1pt minus 1pt}\xBB. Les variantes \idx\medskip et \idx\bigskip ins\xE8rent des espaces verticales \xE9gales respectivement \xE0 2 fois et 4 fois \idx\smallskipamount.
+
+Les macros \idx\smallbreak, \idx\medbreak et \idx\bigbreak se comportent comme leurs s\oe urs en \xABskip\xBB mais elles v\xE9rifient tout d'abord que la pr\xE9c\xE9dente espace verticale qui les pr\xE9c\xE8de est inf\xE9rieure \xE0 celle qui doit \xEAtre ins\xE9r\xE9e. Dans ce cas seulement, ces macros favorisent une coupure de page (par l'insertion d'une \idx{p\xE9nalit\xE9} de $-50$, $-100$ ou $-200$), suppriment la pr\xE9c\xE9dente espace verticale et ins\xE8rent l'espace par l'interm\xE9diaire de \idx\smallskip, \idx\medskip et \idx\bigskip.
+
+\subsubsection{\texttt{\textbackslash relax}}
+La primitive \idx\relax est la plus simple \xE0 comprendre puisqu'elle ne provoque aucune action. Elle est cependant utile notamment pour marquer clairement la fin d'un nombre ou d'une dimension et \xE9vite que \TeX{} n'aille chercher des choses au-del\xE0. Elle fait aussi partie, mais de fa\xE7on optionnelle, de la syntaxe des primitives \idx\numexpr et \idx\dimexpr de \idx\eTeX{} (voir pages~\pageref{numexpr} et \pageref{dimexpr}).
+
+\subsubsection{Commandes de fontes}
+Les commandes suivantes, programm\xE9es dans le format plain-\TeX, agissent comme des \xAB bascules \xBB et s\xE9lectionnent une forme de fonte :
+
+\begin{centrage}
+\small
+\begin{tabular}{ccc}\hline
+	Commande \TeX & \xC9quivalent \LaTeX & Exemple\\\hline
+	\idx\bf & \idx\bfseries & \bf fonte en gras\\
+	\idx\it & \idx\itshape & \it fonte italique\\
+	\idx\tt & \idx\ttfamily & \tt fonte \xE0 chasse fixe\\
+	\idx\sc & \idx\scshape & \sc fonte petite majuscule\\\hline
+\end{tabular}
+\end{centrage}
+
+Par ailleurs, en \idx*{mode!math\xE9matique}mode math\xE9matique, la primitive \idx\scriptstyle fonctionne \xE9galement comme une bascule au niveau de la taille de la fonte qui est affich\xE9e dans la taille des exposants. De la m\xEAme fa\xE7on, \idx\scriptscriptstyle s\xE9lectionne une taille encore plus petite, celle des \xAB exposants d'exposants \xBB :
+
+\showcode/3 tailles : $% entre en mode math\xE9matique (espaces ignor\xE9s)
+1^{2^3}% 2 est en taille "\scriptstyle" et 3 en taille "\scriptscriptstyle"
+$% fin du mode math\xA4\idx*{mode!math\xE9matique}\xA4
+
+normal $1$, petit $\scriptstyle 2$, tr\xE8s petit $\scriptscriptstyle 3$.\xA4\idx*\scriptstyle\idx*\scriptscriptstyle\xA4/
+
+\subsubsection{Les boites}
+Venons-en maintenant aux \idx{boite}s, non pas celles que \TeX{} construit automatiquement lors de la composition, mais de celles qui sont mises \xE0 disposition de l'utilisateur pour qu'il puisse enfermer dedans un contenu arbitraire.
+
+\TeX{} met \xE0 disposition trois primitives permettant d'enfermer du mat\xE9riel dans des boites :
+\begin{itemize}
+	\item \idx\hbox\verb|{<contenu>}| enferme le \verb|<contenu>| dans une boite horizontale, \xE9tant entendu que ce contenu ne peut \xEAtre compos\xE9 qu'en mode horizontal\idx*{mode!horizontal} et doit donc \xEAtre exempt de commande sp\xE9cifiquement verticale (\idx\par ou \idx\vskip y sont interdits puisque passant en mode vertical\idx*{mode!vertical});
+	\item \idx\vbox\verb|{<contenu>}| construit une boite verticale dans laquelle chaque \xE9l\xE9ment du \verb|<contenu>| est empil\xE9 sous l'\xE9l\xE9ment pr\xE9c\xE9dent et o\xF9 r\xE8gne le mode vertical \emph{interne}\idx*{mode!vertical interne}. Le \idx{point de r\xE9f\xE9rence} de la boite ainsi obtenue co\xEFncide avec celui du dernier \xE9l\xE9ment (le plus bas donc). Autrement dit, la \idx{ligne de base} de la \idx\vbox co\xEFncidera donc avec la \idx{ligne de base} de l'\xE9l\xE9ment le plus bas. Par cons\xE9quent, s'il y a $n$ \xE9l\xE9ments dans la \idx\vbox, les $n-1$ premiers seront plac\xE9s au-dessus de la \idx{ligne de base} de la ligne courante comme le montre la figure ci-dessous ;
+	\item \idx\vtop\verb|{<contenu>}| proc\xE8de comme \verb|\vbox| sauf que le \idx{point de r\xE9f\xE9rence} de la \idx\vtop co\xEFncide avec celui du \emph{premier} \xE9l\xE9ment (le plus haut). Les $n-1$ derniers \xE9l\xE9ments sont donc au-dessous de la \idx{ligne de base} de la ligne courante.
+\end{itemize}
+
+Voici deux constructions, l'une avec \idx\vbox et l'autre avec \idx\vtop o\xF9 les fronti\xE8res des boites ont \xE9t\xE9 rendues visibles et o\xF9 les points de r\xE9f\xE9rences de chaque boite ont \xE9t\xE9 symbolis\xE9s par un point \xAB\tikz\draw[fill,black](0.35pt,0pt)circle(1pt);\xBB. Pour les besoins de l'exemple, chaque boite contient trois \xE9l\xE9ments.
+
+\begin{centrage}\footnotesize
+	Voici une \idx\vbox : \drawbox{\vbox{\hbox{\drawbox{La premi\xE8re ligne}}\hbox{\drawbox{La deuxi\xE8me}}\hbox{\drawbox{Et la troisi\xE8me}}}} puis une \idx\vtop : \drawbox{\vtop{\hbox{\drawbox{La premi\xE8re ligne}}\hbox{\drawbox{La deuxi\xE8me}}\hbox{\drawbox{Et la troisi\xE8me}}}}
+\end{centrage}
+
+Le mode en cours dans ces boites est le mode \emph{interne}\idx*{mode!interne}. Il s'agit du mode horizontal interne\idx*{mode!horizontal interne} pour \idx\hbox et du mode vertical interne\idx*{mode!vertical interne} pour \idx\vbox et \idx\vtop.\grandsaut
+
+Une boite construite avec l'une des trois primitives \idx\hbox, \idx\vbox ou \idx\vtop est \emph{ins\xE9cable}. Il n'existe donc aucun m\xE9canisme qui permet de couper une boite ainsi construite\label{boite.insecable}. Il est donc n\xE9cessaire d'\xEAtre prudent sur les d\xE9bordements\idx*{d\xE9passement (marge)} qui peuvent en r\xE9sulter :
+
+\begin{itemize}
+	\item en mode horizontal\idx*{mode!horizontal}, ces d\xE9bordements ont lieu dans la marge de droite ;
+	\item en mode vertical interne\idx*{mode!vertical interne}, ils ont lieu dans la marge inf\xE9rieure.
+\end{itemize}
+
+{\hfuzz=\maxdimen Pour illustrer ce propos, voici ce qui arrive si on tente d'enfermer ces \hbox{\bfseries mots en gras} dans une \idx\hbox. On peut constater que la coupure de ligne n'a pu se faire et que la boite d\xE9passe dans la marge de droite. Cela signifie que malgr\xE9 tous ses efforts pour comprimer ou \xE9tirer les espaces, couper des mots, mixer ces possibilit\xE9s pour examiner plusieurs solutions, \TeX{} n'a pu composer le paragraphe\idx*{paragraphe!composition} pour faire en sorte que cette \idx\hbox se trouve entre les fronti\xE8res du texte. Dans le cas pr\xE9sent, cet \xE9chec est d\xFB \xE0 la trop grande largeur de la boite et au fait qu'elle se situe \xE0 un endroit proche du d\xE9but du paragraphe, o\xF9 la latitude d'organiser diff\xE9remment ce qui pr\xE9c\xE8de est assez r\xE9duite. \TeX{} avertit l'utilisateur qu'une anomalie dans la composition du paragraphe a eu lieu par un message dans le \idx[!log]{fichier} \verb|log|: c'est le fichier produit par \TeX{} lors de la compilation d'un code source. Ce fichier contient des informations de compilation et a le m\xEAme nom que le fichier compil\xE9 mais porte l'extension \xAB\texttt{.log}\xBB. Concernant ce d\xE9bordement, on lit dans ce ficher \xAB\texttt{Overful \string\hbox{} (9.74199pt too wide) in paragraph}\xBB, ce qui signifie qu'une boite horizontale (la boite horizontale dont il est question est ici la ligne en cours) est trop large de 9.74199pt par rapport \xE0 la largeur du texte.\par}
+
+\section{Demandez le programme}
+Le chemin choisi pour aborder la programmation en \TeX{} va sembler, c'est s\xFBr, long et ingrat. Il ob\xE9it cependant \xE0 une logique qui apparaitra plus tard au lecteur. Les parties I et II ne sont pas consacr\xE9es \xE0 la programmation, mais aux nombreuses sp\xE9cificit\xE9s du langage \TeX{} sans lesquelles il est impossible de construire le moindre programme. C'est par souci de clart\xE9 et pour b\xE2tir des bases solides que ces sp\xE9cificit\xE9s sont abord\xE9es \emph{avant} d'entrer dans le vif du sujet. Renoncer \xE0 ces explications pr\xE9liminaires aurait conduit \xE0 d'innombrables digressions, chacune apparaissant \xE0 une nouvelle sp\xE9cificit\xE9, et troublant plus le discours qu'autre chose. Ainsi, la partie I montrera comment et selon quelles r\xE8gles \TeX{} lit le code source pour le transformer en mati\xE8re exploitable que sont les \idx{token}s. La partie suivante exposera les nombreuses sp\xE9cificit\xE9s des macros de \TeX{} et comment les construire afin de maitriser cet outil fondamental de programmation.
+
+Ce n'est qu'ensuite, \xE0 la partie III, que nous nous lancerons dans le grand bain et commencerons \xE0 b\xE2tir des algorithmes. Nous verrons, \xE0 l'aide d'algorithmes relativement peu complexes, quelles m\xE9thodes de programmation nous pouvons mettre en \oe uvre en \TeX{} et quels \xE9cueils nous devons \xE9viter. La partie IV s'inscrit dans la continuit\xE9 de la partie III, mais les m\xE9thodes employ\xE9es diff\xE8rent en ce sens que la granularit\xE9 de la lecture du code effectu\xE9e par les macros sera plus fine.
+
+Enfin, la derni\xE8re partie sera consacr\xE9e \xE0 des algorithmes un peu plus complexes mettant \xE0 profit les notions vues jusqu'alors.
+%|                                                                            |
+%|                              Fin introduction                              |
+%|____________________________________________________________________________|
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                                  Partie 1                                  |
+%|                                                                            |
+\defpartcomment{\lettrine[lines=3,slope=4pt,nindent=0pt]{\libertineInitialGlyph{A}}{\kern -5pt vant} d'entrer dans le vif du sujet, il nous faut comprendre un des m\xE9canismes fondamentaux de \TeX{}, le premier dont il est question lorsque \TeX{} fonctionne : comment lit-il le code qui est tap\xE9 par l'utilisateur ? Et qu'est-ce r\xE9ellement du code tap\xE9 par l'utilisateur ? Les r\xE9ponses \xE0 ces questions non triviales permettent non seulement de lever une petite partie du myst\xE8re qui entoure le fonctionnement de \TeX{} mais surtout posent des bases essentielles.}
+
+\part{\TeX{} et le code source}
+\chapter{Comment \TeX{} lit-il le code source ?}
+Pour bien r\xE9pondre \xE0 cette question, il faut d'abord d\xE9finir ce qu'est du \xABcode tap\xE9 par l'utilisateur\xBB. Ce code, la plupart du temps stock\xE9 dans un fichier, est consid\xE9r\xE9 et lu par \TeX{} \idx{octet}\footnote{Un octet est une suite de 8 bits. Cette suite peut \xEAtre comprise comme un nombre constitu\xE9 de 8 chiffres en base 2. Si l'on convertit ce nombre en base 10 alors, ce nombre peut varier de $2^0-1$ \xE0 $2^8-1$, c'est-\xE0-dire de 0 \xE0 255 ou \Hex{00} \xE0 \Hex{FF} en hexad\xE9cimal.} par \idx{octet}; c'est d'ailleurs ainsi qu'il est stock\xE9 sur les disques durs de nos ordinateurs. Ainsi la r\xE9solution de lecture de \TeX{} est toujours la m\xEAme, le code tap\xE9 par l'utilisateur est vu par \TeX{} comme une suite d'\idx{octet}s.
+\grandsaut
+
+Un \xAB\idx{\xE9diteur}\xBB est un logiciel totalement ind\xE9pendant de \TeX{} dont les fonctions les plus basiques sont de permettre la saisie de \emph{texte} et la sauvegarde de ce texte dans un fichier. Il existe des quantit\xE9s d'\xE9diteurs\footnote{Citons pour les plus reconnus vim et emacs du c\xF4t\xE9 de UNIX/GNU-linux et notepad++ du c\xF4t\xE9 de Windows.} diff\xE9rents, avec des fonctions plus ou moins nombreuses, parfois pl\xE9thoriques, certains \xE9tant m\xEAme sp\xE9cialis\xE9s dans la saisie de code \TeX\footnote{L\xE0 aussi, il y a du monde : auc\TeX{} qui est une extension d'emacs pour le sp\xE9cialiser pour \TeX/\LaTeX, \TeX macs, kile, \TeX maker, \TeX works, etc.}. Lorsqu'on demande \xE0 l'\xE9diteur d'enregistrer dans un fichier le texte que l'on a tap\xE9, l'\xE9diteur a la charge de \emph{convertir} les caract\xE8res tap\xE9s par l'utilisateur en une suite d'\idx{octet}s qui seront enregistr\xE9s sur le disque dur sous forme d'un fichier texte.
+
+Pour comprendre comment cette conversion est faite et quelle est la signification de ces \idx{octet}s, il faut savoir \xE0 quel \xAB\idx{encodage}\xBB ob\xE9it l'\xE9diteur lors de cette conversion. Un \idx{encodage} est une convention qui lie de fa\xE7on biunivoque un caract\xE8re \xE0 un (parfois plusieurs) \idx{octet}. Il est important de comprendre que c'est l'\emph{utilisateur}, en param\xE9trant son \xE9diteur, qui d\xE9cide quel \idx{encodage} il d\xE9sire utiliser, m\xEAme si \xE9videmment, un choix par d\xE9faut est toujours s\xE9lectionn\xE9 si l'on n'a pas fait la d\xE9marche de modifier le param\xE8tre ad\xE9quat.
+\grandsaut
+
+L'\idx{encodage} ASCII\idx*{encodage!ASCII}\footnote{ASCII est l'acronyme pour \xABAmerican Standard Code for Information Interchange\xBB.} est commun \xE0 l'immense majorit\xE9 des autres \idx{encodage}s ce qui fait que l'ASCII joue le r\xF4le de plus petit d\xE9nominateur commun. Cette convention ASCII ne s'occupe que des \idx{octet}s compris entre 0 et 127 (ou \Hex{00} et \Hex{7F} en hexad\xE9cimal). \TeX{} reconnait nativement l'ASCII dont on voit dans la table ci-dessous la correspondance entre \idx{octet}s et caract\xE8res. Pour toutes les impl\xE9mentations de \TeX{}, la relation entre \idx{octet} et caract\xE8re affichable qui figure dans cette table est valide :
+
+\def\carnonaff{\itshape}
+\begin{centrage}
+	\noindent
+	\footnotesize
+	\def\?#1{\ttfamily\bfseries x#1}%
+	\newcount\charcnt \charcnt=-17
+	\def\!{\global\advance\charcnt1 }%
+	\def\:{\char\charcnt}%
+	\let\^\carnonaff% marque un caract\xE8re non affichable
+	\newcolumntype G{m{\dimexpr(\linewidth-18\arrayrulewidth)/17\relax}}%
+	\begin{tabular}{|@{}>{\columncolor{gray!40}[0pt][0pt]\hfill\ttfamily\bfseries}G<{x\hfill\null}@{}|*{16}{@{}>{\!\hfill\vrule height3.3ex depth.8ex width0pt }G<{\hfill\unless\ifnum\charcnt<0 \vtop{\kern1.5pt\normalfont\tiny\llap{\number\charcnt\kern.5pt}\kern1pt}\fi\null}@{}|}}
+	\hline
+		\rowcolor{gray!40}[0pt][0pt]\multicolumn1{|@{}G@{}|}{\cellcolor{white}}
+		&\?0 &\?1 &\?2 &\?3 &\?4 &\?5 &\?6 &\?7 &\?8 &\?9 & \?A& \?B&\?C &\?D &\?E & \?F\\\hline
+		0 & \^NUL&\^SOH &\^STX &\^ETX &\^EOT &\^ENQ &\^ACK &\^BEL & \^BS &\^HT  & \^LF & \^VT & \^FF & \^CR & \^SO & \^SI \\\hline
+		1 & \^DLE&\^DCI & \^DC2& \^DC3& \^DC4& \^NAK& \^SYN& \^ETB& \^CAN& \^EM & \^SUB& \^ESC& \^FS & \^GS & \^RS & \^US \\\hline
+		2 & SP & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: \\\hline
+		3 & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: \\\hline
+		4 & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: \\\hline
+		5 & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: \\\hline
+		6 & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: \\\hline
+		7 & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \: & \^DEL\\\hline
+	\end{tabular}
+\end{centrage}
+
+Dans ce tableau, les cases gris\xE9es portent les deux chiffres hexad\xE9cimaux qui formeront le num\xE9ro de l'octet. Le nombre en bas \xE0 droite de chaque case est le num\xE9ro de l'octet en base 10. Par exemple, le caract\xE8re \xABA\xBB correspond \xE0 l'octet \Hex{41} dont la valeur d\xE9cimale est 65.
+
+On remarque que quelques octets codent des caract\xE8res non affichables. Ceux-ci sont affich\xE9s en italique\footnote{Les acronymes dans les cases des caract\xE8res non imprimables correspondent \xE0 des noms qui ont \xE9t\xE9 donn\xE9s \xE0 ces octets lors de la cr\xE9ation de cet \idx{encodage}. Pour la plupart, ces octets \xE9taient ins\xE9r\xE9s dans des flux de donn\xE9es lors de t\xE9l\xE9transmission et avaient une signification li\xE9e \xE0 la communication entre deux ordinateurs distants. Par exemple, l'octet {\carnonaff EOT\/} signifie \xAB End Of Transmission\xBB c'est-\xE0-dire \xAB Fin de Transmission\xBB, {\carnonaff NAK\/} signifie \xABNegative Acknowledge\xBB pour \xABAccus\xE9 de r\xE9ception n\xE9gatif\xBB. Ces fonctions sont \xE9videmment sans objet pour un traitement de texte comme \TeX{}. Ces caract\xE8res n'ont donc pas de signification particuli\xE8re pour \TeX{} \xE0 l 'exception de quelques caract\xE8res non imprimables dont la fonction est rest\xE9e la m\xEAme : {\carnonaff HT\/} pour \xABtabulation horizontale\xBB (le caract\xE8re ins\xE9r\xE9 avec la touche \xABTab\xBB \bioLegacyKeyGlyph{T_a_b}), {\carnonaff LF\/} pour \xABsaut de ligne\xBB et {\carnonaff CR\/} pour \xABretour charriot\xBB.} dans la table. Ils ont des codes hexad\xE9cimaux compris entre \Hex{00} et \Hex{1F} inclus auxquels il faut rajouter le caract\xE8re de code \Hex{7F}.
+\grandsaut
+
+Pendant la compilation, \xE0 chaque fois que \TeX{} lit un \idx{octet} --~pour l'instant, disons par abus de langage un \xABcaract\xE8re\xBB~--, il lui affecte une bonne fois pour toutes un \xABcode de cat\xE9gorie\xBB ou \xAB\idx{catcode}\xBB et de fait, chaque caract\xE8re lu dans le fichier a donc \emph{deux} codes pour \TeX:
+\begin{itemize}
+	\item le \idx{code de caract\xE8re}, c'est-\xE0-dire la valeur de l'\idx{octet} lu dans le code source et qui est li\xE9 \xE0 la table ASCII vue pr\xE9c\xE9demment;
+	\item le code de cat\xE9gorie\idx*{catcode} qui est affect\xE9 par \TeX{} lors de sa lecture. Ces codes de cat\xE9gorie sont des entiers qui vont de 0 \xE0 15 et qui donnent au caract\xE8re des propri\xE9t\xE9s qui sont celles de la cat\xE9gorie \xE0 laquelle il appartient.
+\end{itemize}
+
+Voici les diff\xE9rentes \idx{cat\xE9gories} ainsi que pour chacune, les caract\xE8res qui les peuplent par d\xE9faut :
+
+\begin{centrage}
+	\label{catcode.table}\small
+	\let\^\carnonaff% marque un caract\xE8re non affichable
+	\LTpre\parskip \LTpost\parskip\idx*{catcode!table des catcodes}
+	\begin{longtable}{>{\leftskip0ptplus1fill \rightskip\leftskip}m{1.5cm}m{4.5cm}m{3cm}}\hline
+
+ 		N\xB0{} de\par cat\xE9gorie & Signification & Caract\xE8res\par concern\xE9s\\\hline\endhead
+		0 & \idx{caract\xE8re d'\xE9chappement} & \texttt\textbackslash\\
+		1 & d\xE9but de groupe & \ttfamily\{\\
+		2 & fin de groupe & \ttfamily\}\\
+		3 & d\xE9limiteur de mode math\xE9matique\idx*{mode!math\xE9matique} & \ttfamily\$\\
+		4 & tabulation d'alignement & \ttfamily\&\\
+		5 & retour charriot & \^LF\\
+		6 & caract\xE8re de param\xE8tre & \ttfamily\#\\
+		7 & exposant & \ttfamily\string^\\
+		8 & indice & \ttfamily\string_\\
+		9 & caract\xE8re ignor\xE9 & \^NUL\\
+		10 & \idx{espace} & SP et \^HT\\
+		11 & lettres & \texttt{A...Z}\quad et\quad\texttt{a...z}\\
+		12 & autres caract\xE8res &\\
+		&\qquad-- chiffres & \ttfamily0 1 2 3 4 5 6 7 8 9\\
+		&\qquad-- signes de ponctuation & \ttfamily\string: . \string; , \string? \string! \string' \string"\\
+		&\qquad-- signes math\xE9matiques & \ttfamily + - * / = < >\\
+		&\qquad-- autres signes &\ttfamily [ ] ( ) | @ \string`\\
+		13 & caract\xE8re actif & \ttfamily\string~\\
+		14 & caract\xE8re de commentaire & \ttfamily\%\\
+		15 & caract\xE8re invalide & \^DEL\\
+		\hline
+	\end{longtable}
+\end{centrage}
+
+Dans toute la suite du livre, sauf indication contraire, lorsqu'il est dit par abus de langage \xAB lettre \xBB ou bien \xAB accolade ouvrante \xBB, il est sous-entendu \xAB caract\xE8re de catcode 11\idx*{catcode!11 (lettre)} \xBB ou \xAB caract\xE8re de catcode 1\idx*{catcode!1 (accolade)} \xBB.
+
+Comme on le voit, certaines cat\xE9gories sont tr\xE8s peupl\xE9es (celles dont le num\xE9ro est 11 ou 12) alors que d'autres ne contiennent qu'un seul \xE9l\xE9ment. Ceci s'explique par le fait que seules les cat\xE9gories de num\xE9ro 10, 11 et 12 comportent des caract\xE8res \emph{affichables} pour \TeX. Les autres ne comportent que des caract\xE8res qui commandent une action \xE0 \TeX{}, par exemple de passer en mode math\xE9matique\idx*{mode!math\xE9matique} pour le caract\xE8re \xAB\verb-$-\xBB. Comme il n'y a pas de raison pour que plusieurs caract\xE8res rev\xEAtent cette propri\xE9t\xE9, il est logique de ne trouver qu'un seul caract\xE8re dans la cat\xE9gorie n\xB03. Le m\xEAme raisonnement s'applique aux autres cat\xE9gories ne comportant qu'un seul caract\xE8re.
+
+L'\idx{espace}, bien qu'affichable, se trouve dans une cat\xE9gorie \xE0 part, car il ob\xE9it \xE0 des r\xE8gles diff\xE9rentes que celles des autres caract\xE8res affichables, notamment lors de la lecture du code source :
+
+\label{espaces.consecutifs}\begin{regle}
+Lorsque plusieurs espaces\idx*{espace!cons\xE9cutifs} (ou plus g\xE9n\xE9ralement \xABcaract\xE8res de catcode 10\xBB\idx*{espace!catcode 10})\idx*{catcode!10 (espace)} se suivent dans le code source, \TeX{} ne prend en compte que le premier d'entre eux et ignore les autres.
+
+Si une ligne de code source commence par des espaces\idx*{espace!d\xE9but de ligne}, ceux-ci sont ignor\xE9s.
+
+Plain-\TeX{} et \LaTeX{} assignent au caract\xE8re de tabulation ({\carnonaff HT\/}) le catcode de 10 ce qui signifie que ce caract\xE8re rev\xEAt toutes les propri\xE9t\xE9s de l'espace.
+\end{regle}
+
+Pour fixer les id\xE9es, supposons que \TeX{} ait \xE0 lire le code suivant :
+
+\centrecodespc-\hbox{Et $x$ vaut  3,5.}-
+
+\noindent Au fur et \xE0 mesure de sa lecture, il attribuera \xE0 chaque caract\xE8re le code de cat\xE9gorie en vigueur au moment o\xF9 il le lit et agira en cons\xE9quence. Ce code de cat\xE9gorie est attribu\xE9 de fa\xE7on \emph{d\xE9finitive} et ne peut pas \xEAtre chang\xE9 ensuite ; il s'agit d'un m\xE9canisme incontournable sur lequel il faut insister :
+
+\label{catcode.inalterable}\begin{regle}
+	D\xE8s que \TeX{} lit un caract\xE8re, il lui affecte de fa\xE7on inalt\xE9rable un \idx*{catcode}code de cat\xE9gorie.
+\end{regle}
+
+Si lors de la lecture, les catcodes en vigueur sont ceux expos\xE9s dans le tableau ci-dessus, voici sous chaque caract\xE8re, le catcode qui lui sera affect\xE9 :
+
+\def\falsespcverb{\leavevmode\vrule width0.2pt height .5ex depth 0pt
+	\vrule width.75em height0.4pt depth 0pt
+	\vrule width0.2pt height .5ex depth 0pt }
+\begingroup
+	\hfill
+	\def~#1#2{%
+		\hbox{%
+			\footnotesize
+			\vtop{\offinterlineskip\hbox to1em{\hss\ttfamily\strut#1\hss}\hbox to1em{\hss\tiny#2\hss}}%
+		}%
+	}
+	~\textbackslash0~h{11}~b{11}~o{11}~x{11}%
+	~\{1~E{11}~t{11}~\falsespcverb{10}~{\string$}{3}~x{11}%
+	~{\string$}{3}~\falsespcverb{10}~v{11}~a{11}%
+	~u{11}~t{11}~\falsespcverb{10}~3{12}~,{12}~5{12}~.{12}%
+	~\}2\hfill\null
+\endgroup
+\grandsaut
+
+Un caract\xE8re peut \xEAtre tap\xE9 sous forme habituelle comme lorsqu'on tape un \xAB\verb-a-\xBB, mais on peut aussi utiliser \xAB\verbidx[|(]{^^}\xBB. En effet, si \TeX{} voit deux caract\xE8res \emph{identiques} dont le code de cat\xE9gorie est \number\catcode`\^{} (celui du caract\xE8re de mise en exposant) et si ces deux caract\xE8res sont suivis d'un caract\xE8re dont le code --~appelons-le $c$~-- est compris entre 0 et 63 inclus, alors \TeX{} lit le tout comme \xE9tant le caract\xE8re dont le code est $c+64$. Par exemple, \xAB\verb-^^:-\xBB est le caract\xE8re \xAB^^:\xBB. Il est rigoureusement \xE9quivalent de taper \xAB^^:\xBB ou \xAB\verb-^^:-\xBB et ce, quel que soit l'endroit o\xF9 l'on se trouve dans le code source.
+
+Sym\xE9triquement, si le code de caract\xE8re $c$ est compris entre 64 et 127 inclus, \TeX{} remplace le tout par le caract\xE8re de code $c-64$. Et donc, il est \xE9quivalent de taper \xAB\verb-^^z-\xBB ou \xAB\string^^z\xBB.
+
+Ce qui est \xE9crit dans les deux paragraphes pr\xE9c\xE9dents nous conduit donc \xE0 cette r\xE8gle :
+
+\begin{regle}
+Lorsqu'on \xE9crit \xAB\verb-^^<car>-\xBB dans le code source, tout se passe donc comme si \TeX{} voyait le caract\xE8re se trouvant 4 lignes plus haut ou plus bas dans la table ASCII, selon que \verb-<car>- se trouve dans la partie basse ou haute de cette table.
+
+Si les \emph{deux} caract\xE8res qui suivent \verb-^^- forment un nombre hexad\xE9cimal \xE0 deux chiffres minuscules pris parmi \xAB\verb-0123456789abcdef-\xBB, alors \TeX{} remplace ces 4 caract\xE8res par le caract\xE8re ayant le code hexad\xE9cimal sp\xE9cifi\xE9. Avec cette m\xE9thode, on peut donc facilement acc\xE9der \xE0 n'importe quel caract\xE8re. Le caract\xE8re \xABz\xBB peut aussi s'\xE9crire \xAB\verb-^^7a-\xBB.
+\end{regle}
+
+Ainsi, le caract\xE8re \xABt\xBB \xE9tant appari\xE9 via \verb-^^- avec un caract\xE8re affichable (en l'occurrence \xAB4\xBB qui se trouve 4 lignes plus haut dans la table ASCII), \xABt\xBB peut donc \xEAtre tap\xE9 dans le code de 3 fa\xE7ons \xE9quivalentes : \xAB\verb-t-\xBB ou \xAB\verb-^^4-\xBB ou \xAB\verb-^^74-\xBB. Si l'on voulait rendre le code myst\xE9rieux ou difficilement lisible, voici comment on pourrait \xE9crire le mot \xABtex\xBB :
+\begin{itemize}
+	\item \verb-^^4^^%^^8-
+	\item \verb-^^74^^65^^78-
+\end{itemize}
+
+La seule petite ambig\xFCit\xE9 qui subsiste dans cette belle m\xE9canique est que l'on ne peut pas \xE9crire un \xABt\xBB sous la forme \xAB\verb|^^4|\xBB puis le faire suivre du caract\xE8re \xAB5\xBB. En effet, cela formerait la suite de caract\xE8res \xAB\verb|^^45|\xBB que \TeX{} interpr\xE8terait comme \xE9tant le caract\xE8re de code hexad\xE9cimal \Hex{45} qui est \xABE\xBB\verbidx*[|)]{^^}.
+
+Au-del\xE0 de l'originalit\xE9 de cette m\xE9thode alternative pour \xE9crire des caract\xE8res dans le code source, ce qu'il faut en retenir est qu'elle peut \xEAtre tr\xE8s utile pour \xE9crire des caract\xE8res non affichables qui de toute fa\xE7on, seraient difficilement accessibles au clavier. Ainsi, le caract\xE8re de tabulation {\carnonaff HT} s'\xE9crit \xAB\verbidx[ (tabulation)]{^^I}\xBB, le retour charriot {\carnonaff CR} \xAB\verbidx[ (retour charriot)]{^^M}\xBB, etc.
+\grandsaut
+
+On peut aussi \emph{afficher} un caract\xE8re avec la primitive \idx\char suivie du num\xE9ro du code de caract\xE8re. Ainsi, \verb|\char97| affiche un \xAB\char97\xBB mais au contraire de la m\xE9thode avec \verb|^^|, \verb|\char97| ne peut pas \xEAtre utilis\xE9 dans le code source \xE0 la place d'une lettre. Autant \xAB\verb|\p^^61r|\xBB et \xAB\verb|\par|\xBB sont \xE9quivalents, autant il n'est pas question d'\xE9crire \xAB\verb|\p\char65r|\xBB \xE0 la place de \verb|\par| dans le code source, car ceci serait interpr\xE9t\xE9 comme la commande \verb|\p|, suivie de \verb|\char65|, suivi de \xABr\xBB.
+\grandsaut
+
+Enfin, il faut d\xE9finir ce qu'est une \xABligne de code source\xBB. Pour \TeX{}, une ligne de code est constitu\xE9e par les caract\xE8res qui se trouvent avant la prochaine \xAB marque de \idx{fin de ligne} \xBB\label{marque.fin.ligne}. Cette marque est une convention qui d\xE9pend du syst\xE8me d'exploitation :
+
+\begin{itemize}
+	\item pour Windows, une marque de fin de ligne est constitu\xE9e des octets \Hex{0D}\Hex{0A}, c'est-\xE0-dire de {\carnonaff CR} suivi de {\carnonaff LF} (not\xE9 \xABCRLF\xBB);
+	\item pour GNU-linux, cette marque est l'octet \Hex{0A} (LF);
+	\item enfin, pour MAC OS X, cette marque est l'octet \Hex{0D} (CR).
+\end{itemize}
+
+L'ex\xE9cutable \texttt{pdftex} consid\xE8re comme marque de fin de ligne les s\xE9quences suivantes : LF, CR, CRLF et LFCR. Les \idx[!fin de ligne]{espace}s qui pr\xE9c\xE8dent la marque de \idx{fin de ligne} sont supprim\xE9s en m\xEAme temps que cette marque et \TeX{} ins\xE8re \xE0 la place un caract\xE8re sp\xE9cial dont le code de caract\xE8re est contenu dans la primitive \idx\endlinechar. Habituellement, ce code vaut \number`\^^M{}, celui du caract\xE8re retour charriot\verbidx*[ (retour charriot)]{^^M}.
+
+\label{catcode.5}
+\begin{regle}
+Dans la ligne courante, si un caract\xE8re de catcode \number\catcode`\%\relax{} (caract\xE8re de commentaire, g\xE9n\xE9ralement \cidx[ (caract\xE8re de commentaire)]\%) ou \number\catcode`\^^M\relax{} (retour charriot, g\xE9n\xE9ralement \verb|^^M|\verbidx*[ (retour charriot)]{^^M}) apparait, alors, ce caract\xE8re ainsi que tout ce qui va jusqu'\xE0 la fin de la ligne est ignor\xE9, y compris le caract\xE8re de code \idx\endlinechar ins\xE9r\xE9 \xE0 la fin de la ligne.
+\end{regle}
+
+Les caract\xE8res de catcode 5 ob\xE9issent \xE0 une r\xE8gle particuli\xE8re :
+
+\label{regle.catcode5}\begin{regle}
+Un caract\xE8re de catcode 5 est interpr\xE9t\xE9 comme un \idx[!catcode 5]{espace}.\idx*{catcode!5 (retour charriot)}\idx*{espace!catcode 5}
+
+Deux caract\xE8res de catcode 5 cons\xE9cutifs sont transform\xE9s en la s\xE9quence de contr\xF4le \idx\par\verbidx*[ cons\xE9cutifs]{^^M}.
+\medbreak
+
+Cela signifie qu'un retour charriot\verbidx*[ (retour charriot)]{^^M} est vu comme un \idx[!fin de ligne]{espace}, sauf s'il est pr\xE9c\xE9d\xE9 du caract\xE8re \cidx\% et que deux retours charriots cons\xE9cutifs (symbolis\xE9s dans le code source par une ligne vide) seront \xE9quivalents \xE0 \idx\par.
+\end{regle}
+
+On peut localement modifier le caract\xE8re de code \idx\endlinechar pour obtenir des effets sp\xE9ciaux en tenant compte de la r\xE8gle suivante :
+
+\begin{regle}
+Si \idx\endlinechar est n\xE9gatif ou sup\xE9rieur \xE0 255, aucun caract\xE8re n'est ins\xE9r\xE9 aux fins de lignes.
+\end{regle}
+
+Voici une illustration de cette r\xE8gle o\xF9 l'on teste le comportement normal, puis on met \idx\endlinechar \xE0 $-1$ et enfin \xE0 \number`\X{} (qui est le code de caract\xE8re de \xABX\xBB) :
+
+{\endlinechar13
+\showcode|%%% comportement normal %%%
+a) comportement normal :
+Ligne 1
+Ligne 2
+
+Ligne 3
+\medbreak\xA4\idx*\medbreak\xA4
+b) Aucun caract\xE8re de fin de ligne :\xA4\idx*{caract\xE8re de fin de ligne}\xA4
+%%% aucune insertion en fin de ligne %%%
+\endlinechar=-1 \xA4\idx*\endlinechar\xA4
+Ligne 1
+Ligne 2
+
+Ligne 3\endlinechar13
+
+\medbreak\xA4\idx*\medbreak\xA4
+c) "X" comme caract\xE8re de fin de ligne :\xA4\idx*{caract\xE8re de fin de ligne}\xA4
+%%% "X" est ins\xE9r\xE9 \xE0 chaque fin de ligne
+\endlinechar=88
+Ligne 1
+Ligne 2
+
+Ligne 3|}
+
+On peut notamment remarquer que lorsque \idx\endlinechar est n\xE9gatif, tout se passe comme si les lignes se terminaient toutes par le \idx[|voir{\xAB\texttt{\char37}\xBB}]{caract\xE8re de commentaire} \cidx\%, de catcode \number\catcode`\%.
+
+\chapter{Octets dont le bit de poids fort est 1}
+Venons-en maintenant \xE0 la partie de la table des caract\xE8res qui se situe apr\xE8s le num\xE9ro 128, c'est-\xE0-dire dont la repr\xE9sentation en base 2 est \bin{1xxxxxxx} et dont le bit le le plus \xE0 gauche, celui qui a le plus de \xABpoids\footnote{Dans l'\xE9criture moderne des nombres, dite \xABde position\xBB, les chiffres ont une influence li\xE9e \xE0 leur position dans le nombre. En \xE9criture d\xE9cimale, nous avons pris comme convention qu'un nombre, par exemple \xE9crit avec 3 chiffres \xAB$\overline{\text{\textit{abc}}}$\xBB, est \xE9gal \xE0 la somme $a\times100+b\times10+c\times1$. Le coefficient d'un chiffre (ou son \xABpoids\xBB) est une puissance de 10 dont l'exposant est d'autant plus grand que la place du chiffre est \xE0 gauche : $10^2$, $10^1$ et $10^0$. On dit que le chiffre $a$ a un \xABpoids\xBB fort puisque plus important que celui des chiffres $b$ ou $c$.
+
+En binaire, c'est le m\xEAme principe sauf que les poids sont les puissances de 2. Si un \idx{octet} s'\xE9crit $\overline{\text{\textit{abcdefgh}}}$, sa valeur en base 10 est $a\times2^7+b\times2^6+\cdots+g\times2^1+h\times2^0$. Le bit \bin{a} est le bit de poids fort tandis que \bin{h} est celui de poids faible.}\xBB, vaut 1. Cette partie de la table n'est pas dans la convention ASCII et donc, d\xE9pend de la convention que l'on veut se donner. Pour nous en France, deux de ces conventions sont utilis\xE9es et d\xE9pendent du codage avec lequel a \xE9t\xE9 enregistr\xE9 le code source. Comme on l'a dit, cet \idx{encodage} doit \xEAtre un surensemble de l'ASCII qui est commun \xE0 tous les \idx{encodage}s.
+
+Historiquement, plusieurs fa\xE7ons de compl\xE9ter la table ASCII ont vu le jour, chacune donnant naissance \xE0 un \idx{encodage} \xE0 part enti\xE8re. Aucune harmonisation n'a jamais \xE9t\xE9 faite et plusieurs \idx{encodage}s sur 8 bits cohabitent encore \xE0 l'heure actuelle. Les plus connus pour les langues occidentales sont :
+
+\begin{itemize}
+	\item \texttt{ansinew} a \xE9merg\xE9 comme \idx{encodage} des syst\xE8mes d'exploitation Windows;
+	\item \texttt{applemac} a \xE9t\xE9 choisi dans la sph\xE8re de la marque Apple jusqu'\xE0 un pass\xE9 r\xE9cent;
+	\item \texttt{latin1}\idx*[|(]{encodage!latin1} a \xE9t\xE9 utilis\xE9 dans le monde Unix/Linux.
+\end{itemize}
+
+Selon ces trois encodages, le caract\xE8re \xAB\xE9\xBB est respectivement plac\xE9 \xE0 l'octet \Hex{E9}, \Hex{8E} et \Hex{E9}.
+\grandsaut
+
+Int\xE9ressons-nous \xE0 l'\idx{encodage} \xAB\latin\xBB ou \xAB\hbox{ISO 8859-1}\xBB\idx*{encodage!latin1}. Cet \idx{encodage} a \xE9t\xE9 cr\xE9\xE9 pour \xEAtre utilis\xE9 avec les langues europ\xE9ennes. Par exemple, l'octet \number"E0{} (ou \Hex{E0} en hexad\xE9cimal) code la lettre \xAB\xE0\xBB. On dispose ainsi de tous les caract\xE8res n\xE9cessaires pour la langue fran\xE7aise\footnote{\xC0 l'exception notable de \xAB\oe \xBB, \xAB\OE \xBB et \xAB\"Y\xBB. Il manque \xE9galement quelques caract\xE8res pour d'autres langues.}. Il faut noter que l'extension pour \LaTeX{} \xAB\verb-inputenc-\xBB\idx*{package!inputenc} charg\xE9e avec l'option \xAB\verb-latin1-\xBB rend plusieurs caract\xE8res actifs (et donc met leur catcode \xE0 13) lorsque l'\idx{encodage} est \latin\idx*{encodage!latin1}. Le caract\xE8re \xAB\xE0\xBB en fait partie et donc, ce caract\xE8re se comporte comme une commande : \verb-inputenc- lui fait ex\xE9cuter un code qui au final, imprime le caract\xE8re \xAB\xE0\xBB. Il est imm\xE9diat que du fait qu'il est actif, le caract\xE8re \xAB\xE0\xBB n'appartient pas \xE0 la cat\xE9gorie des lettres.
+
+Voici la table de l'\idx{encodage} \latin. Seuls les \idx{octet}s sup\xE9rieurs ou \xE9gaux \xE0 128 y figurent puisque ceux qui sont inf\xE9rieurs \xE0 128 sont ceux de la table ASCII :
+
+\begin{centrage}
+	\catcode`\\xB5=12
+	\tabcolsep0pt
+	\footnotesize
+	\par\noindent
+	\def\?#1{\ttfamily\bfseries x#1}%
+	\charcnt=\numexpr128-17
+	\def\:{\global\advance\charcnt1 }%
+	\def\!{\cellcolor{gray!40}}%
+	\let\^\carnonaff% marque un caract\xE8re non affichable
+	\newcolumntype G{m{\dimexpr(\linewidth-18\arrayrulewidth)/17\relax}}%
+	\begin{tabular}{|@{}>{\columncolor{gray!40}[0pt][0pt]\hfill\ttfamily\bfseries}G<{x\hfill\null}@{}|*{16}{@{}>{\:\hfill\vrule height3.3ex depth.8ex width0pt }G<{\hfill\unless\ifnum\charcnt<128 \vtop{\kern1.5pt\normalfont\tiny\llap{\number\charcnt\kern.5pt}\kern1pt}\fi\null}@{}|}}
+	\hline
+		\rowcolor{gray!40}[0pt][0pt]\multicolumn1{|@{}G@{}|}{\cellcolor{white}}
+		&\?0 &\?1 &\?2 &\?3 &\?4 &\?5 &\?6 &\?7 &\?8 &\?9 & \?A& \?B&\?C &\?D &\?E &\?F \\\hline
+		8 & \^PAD& \^HOP&\^BPH &\^NBH &\^IND &\^NEL &\^SSA &\^ESA &\^HTS &\^HTJ &\^VTS &\^PLD &\^PLU &\^RI  &\^SS2 &\^SS3 \\\hline
+		9 & \^DCS& \^PU1& \^PU2& \^STS& \^CCH& \^MW &\^SPA& \^EPA& \^SOS& \^SGCI& \^SCI&\^CSI &\^ST  &\^OSC &\^PM & \^APC\\\hline
+		A &\scalebox{0.8}[1]{NBSP}&^^a1&^^a2&^^a3&^^a4&^^a5&^^a6&\oldparagraph&^^a8&^^a9&^^aa&^^ab&\!$^^ac$&-&^^ae&^^af \\\hline
+		B &^^b0&\!$^^b1$&\!$^^b2$&\!$^^b3$&^^b4&\!$^^b5$&$^^b6$&^^b7&^^b8&\!$^^b9$&^^ba&^^bb&^^bc&^^bd&^^be&^^bf\\\hline
+		C &^^c0&^^c1&^^c2&^^c3&^^c4&^^c5&^^c6&^^c7&^^c8&^^c9&^^ca&^^cb&^^cc&^^cd&^^ce&^^cf\\\hline
+		D &^^d0&^^d1&^^d2&^^d3&^^d4&^^d5&^^d6&\!$^^d7$&^^d8&^^d9&^^da&^^db&^^dc&^^dd&^^de&^^df\\\hline
+		E &^^e0&^^e1&^^e2&^^e3&^^e4&^^e5&^^e6&^^e7&^^e8&^^e9&^^ea&^^eb&^^ec&^^ed&^^ee&^^ef\\\hline
+		F &^^f0&^^f1&^^f2&^^f3&^^f4&^^f5&^^f6&\!$^^f7$&^^f8&^^f9&^^fa&^^fb&^^fc&^^fd&^^fe&^^ff\\\hline
+	\end{tabular}
+\end{centrage}
+\grandsaut
+
+Ici encore, cette partie de la table comporte des caract\xE8res non affichables. Ils se situent entre les codes \Hex{80} et \Hex{9F} inclus auxquels il faut rajouter le caract\xE8re de code \Hex{AD}. Ceux qui se trouvent dans des cases gris\xE9es sont affichables, mais ils doivent \xEAtre utilis\xE9s en mode math\xE9matique\idx*{mode!math\xE9matique}.
+\grandsaut
+
+Bien s\xFBr, certains de ces caract\xE8res ne sont pas directement accessibles au clavier. En fait, les caract\xE8res accessibles au clavier d\xE9pendent de la configuration de chacun. Par exemple, sur \emph{mon} clavier, avec \emph{mon} syst\xE8me d'exploitation et le pilote correspondant au mod\xE8le du clavier, avec le mappage du clavier s\xE9lectionn\xE9 dans les options du syst\xE8me d'exploitation, je peux acc\xE9der au caract\xE8re \xAB\texttt\xE6\xBB avec la combinaison de touches \bioLegacyKeyGlyph{A_l_t_G_r}+\bioLegacyKeyGlyph{A}. Pour le caract\xE8re \xAB$\xB6$\xBB, c'est avec \bioLegacyKeyGlyph{A_l_t_G_r}+\bioLegacyKeyGlyph{R}. Et ainsi de suite\ldots{} En revanche, certains caract\xE8res dans la table ci-dessus me sont inaccessibles, sauf \xE0 les taper via \verb-^^-.
+\grandsaut
+
+L'\idx{encodage} \xAB\utf\idx*[|(]{encodage!UTF8}\footnote{L'acronyme \texttt{UTF8} signifie \xABUnicode Transformation Format 8 bits\xBB.}\xBB permet de coder beaucoup plus que 256 caract\xE8res avec l'in\xE9vitable cons\xE9quence que certains d'entre eux seront cod\xE9s sur plusieurs octets. Le principe de cet \idx{encodage} est assez simple et on peut le d\xE9crire ici :
+\begin{itemize}
+	\item si un caract\xE8re a un code inf\xE9rieur \xE0 128, alors il est cod\xE9 par le m\xEAme \idx{octet} que dans le \idx{encodage} ASCII;
+	\item sinon, il est cod\xE9 sur plusieurs octets : le nombre de bits de poids fort non nuls (au maximum 4) du premier octet indique le nombre d'octets pris au total pour l'\idx{encodage} du caract\xE8re. Par exemple, si un \idx{octet} vaut \bin{1110xxxx} en binaire, les 3 bits de poids fort suivis d'un 0 indiquent que ce caract\xE8re est cod\xE9 sur 3 octets, les 2 octets restants ayant obligatoirement les bits de poids fort \bin{10}, c'est-\xE0-dire qu'ils sont de la forme \bin{10xxxxxx}.
+	
+	Finalement, ce caract\xE8re sera donc cod\xE9 sur 3 octets ayant cette forme : \bin{1110xxxx 10xxxxxx 10xxxxxx}. Il y a donc 16 bits non contraints sur 24. Le \xABcode propre\xBB du caract\xE8re sera constitu\xE9 des 16 bits \bin x.
+\end{itemize}
+
+Si l'on s'int\xE9resse par exemple au caract\xE8re \xAB\xE0\xBB, celui-ci est cod\xE9 en \utf par les 2 octets \Hex{C3} \Hex{A0}. \xC9crits en binaire, on obtient \bin{\textbf{110}00011} \bin{\textbf{10}100000} o\xF9 les bits contraints sont \xE9crits en gras. Il en r\xE9sulte que le code propre du caract\xE8re \xAB\xE0\xBB est \bin{00011100000}. Si on \xE9limine les z\xE9ros inutiles de gauche, on obtient \bin{11100000} qui est l'\idx{octet} \Hex{E0}, celui que l'on retrouve dans la table de l'\idx{encodage} \latin pour la lettre \xAB\xE0\xBB. En effet, en \utf, les caract\xE8res ayant des codes propres compris entre 128 et 255 \emph{doivent} \xEAtre les m\xEAmes que les caract\xE8res qui ont ces codes dans la table de \latin. Enfin, le symbole \xAB\geneuro\xBB est cod\xE9 sur 3 \idx{octet}s en UFT8 : \Hex{E2} \Hex{82} \Hex{AC} qui s'\xE9crit en binaire \bin{\textbf{1110}0010} \bin{\textbf{10}000010} \bin{\textbf{10}101100} et qui donne un code propre de \bin{10000010101100} soit \Hex{20AC}.
+
+Pour \TeX{}, le principe est le m\xEAme qu'avec l'\idx{encodage} \latin, il faut rendre actifs tous les \idx{octet}s qui ont une \xE9criture binaire \bin{110xxxxx} ou \bin{1110xxxx}  ou \bin{11110xxx} et dont les bits non contraints \xAB\bin x\xBB correspondent au d\xE9but du code des caract\xE8res que \TeX{} va prendre en charge. Ensuite, ces caract\xE8res actifs vont lire le (ou les) \idx{octet}(s) suivant(s) et traduire le tout de fa\xE7on \xE0 faire imprimer le caract\xE8re voulu.
+\grandsaut
+
+Ce qu'il faut retenir est que, aussi bien en \latin qu'en \utf, les lettres accentu\xE9es et les caract\xE8res ne figurant pas dans la table ASCII ne sont pas des octets dont le code de cat\xE9gorie est 11 et n'appartiennent donc pas \xE0 la cat\xE9gorie des lettres. De plus, pour ceux qui utilisent l'\idx{encodage} \utf qui tend \xE0 devenir la norme, il ne faut pas perdre de vue que lorsqu'on \xE9crit la lettre \xAB\xE0\xBB dans le code, nous ne voyons qu'un seul caract\xE8re, mais celui-ci est stock\xE9 sur \emph{deux} octets dans le fichier et donc, \TeX{} voit \emph{deux} choses. Il n'y a donc pas \xE9quivalence entre \xABoctet\xBB et \xABcaract\xE8re\xBB et dans tous les cas, \TeX{} ne lit pas le code caract\xE8re par caract\xE8re, mais octet par octet.
+
+Cette derni\xE8re affirmation n'est vraie que pour les trois moteurs \TeX{} (celui \xE9crit par \idx*{Knuth Donald}Donald~\textsc{Knuth}), $\varepsilon$\TeX{}\idx*{moteur!etex} et pdf\TeX{}\idx*{moteur!pdftex}. Outre ces \xAB anc\xEAtres \xBB, encore majoritairement utilis\xE9s malgr\xE9 leur \xE2ge, il existe d\xE9sormais des moteurs plus r\xE9cents qui g\xE8rent nativement l'\idx{encodage} \utf : \XeTeX{} et lua\TeX{}. Ces deux moteurs, entre autres possibilit\xE9s, lisent le code source caract\xE8re \utf par caract\xE8re \utf et il peut donc arriver que plusieurs octets soient lus en un coup pour former une entit\xE9 unique. Malgr\xE9 le progr\xE8s que cela constitue, on consid\xE8rera dans ce livre que l'on utilise un moteur fonctionnant octet par \idx{octet}.\idx*[|)]{encodage!UTF8}\idx*[|)]{encodage!latin1}
+
+\chapter{Codes de cat\xE9gorie}\idx*[|(]{catcode}\idx*[|(]{\catcode}
+Le sujet est vaste et technique puisqu'il touche \xE0 l'un des m\xE9canismes les plus intimes de \TeX. Nous nous contenterons pour l'instant de voir l'essentiel, quitte \xE0 y revenir plus loin au fur et \xE0 mesure de nos besoins. Rappelons que les \xABcat\xE9gories\xBB de \TeX{} sont au nombre de 16 et regroupent des caract\xE8res ayant des propri\xE9t\xE9s communes aux yeux de \TeX{}. Le code de cat\xE9gorie d'un octet lu est la premi\xE8re chose que \TeX{} examine, avant m\xEAme le nombre correspondant \xE0 l'octet lui-m\xEAme puisque le code de cat\xE9gorie d\xE9termine la fa\xE7on dont \TeX{} doit r\xE9agir face \xE0 cet \idx{octet}.
+\grandsaut
+
+Tout d'abord, pour acc\xE9der au code de cat\xE9gorie d'un caract\xE8re, il faut utiliser la primitive \idx\catcode suivie du \emph{\idx{code de caract\xE8re}}. L'ensemble constitue une repr\xE9sentation interne de l'entier \xE9tant le code de cat\xE9gorie du caract\xE8re concern\xE9. La commande \idx\number\label{number} convertit la repr\xE9sentation interne d'un nombre en la repr\xE9sentation affichable habituelle, c'est-\xE0-dire en base 10 et en chiffres arabes. Par exemple, si on veut afficher le code de cat\xE9gorie de \xAB\cidx\$\xBB dont le code de caract\xE8re est \number`\$, on va \xE9crire \xAB\verb-\number\catcode36-\xBB et on obtiendra \xAB\number\catcode36 \xBB.
+
+On peut trouver g\xEAnant de mettre explicitement le code du caract\xE8re apr\xE8s la primitive \idx\catcode. En effet, cela oblige \xE0 aller le chercher dans la table des caract\xE8res ASCII puis le convertir en d\xE9cimal. Cette derni\xE8re \xE9tape, la conversion hexad\xE9cimal vers d\xE9cimal, n'a pas lieu d'\xEAtre faite car \TeX{} comprend nativement les nombres hexad\xE9cimaux\footnote{O\xF9 les lettres qui le composent \emph{doivent} \xEAtre majuscules.}. Pour indiquer qu'un nombre est \xE9crit en base 16, il faut le faire pr\xE9c\xE9der du caract\xE8re \xAB\cidx[ (notation hexad\xE9cimale)]\"\xBB et pour traduire le tout en nombre en \xE9criture arabe en base 10, il faut mettre devant l'ensemble la primitive \idx\number{}:
+
+\showcode/a) \number"1A \qquad b) \number"AB3FE \qquad c) \number"78 \xA4\idx*\number\idx*\qquad\xA4/
+
+Pour obtenir le code de cat\xE9gorie du caract\xE8re \xAB\cidx\$\xBB dont le code de caract\xE8re est \Hex{24}, on peut donc \xE9crire \verb-\number\catcode"24-.
+
+Dans le m\xEAme ordre d'id\xE9e et bien que cela soit assez rarement utile, il faut savoir que \TeX{} comprend aussi les nombres en notation \emph{octale}, c'est-\xE0-dire \xE9crits en base 8. Pour indiquer qu'un nombre est \xE9crit en base 8, il faut le faire pr\xE9c\xE9der de l'apostrophe \xAB\cidx[ (notation octale)]\'\xBB :
+
+\showcode/a) \number'15 \qquad b) \number'674 \qquad c) \number'46\xA4\idx*\number\idx*\qquad\xA4/
+
+Malgr\xE9 ce c\xF4t\xE9 pratique, il faut toujours aller voir la table ASCII pour chercher le code de caract\xE8re. Heureusement, on peut facilement convertir un caract\xE8re en son code \xE9crit en base 10. Pour cela, s'agissant des caract\xE8res de catcode 11\idx*{catcode!11 (lettre)} ou 12\idx*{catcode!12 (autre)}, il faut faire pr\xE9c\xE9der le caract\xE8re de l'apostrophe inverse \boxtoken{`}\cidx*[ (notation de nombre)]{\`} ce qui donnerait \xAB\verb-\number`a-\xBB pour afficher le code de caract\xE8re de \xABa\xBB. Un moyen encore plus s\xFBr qui fonctionne pour \emph{tous} les caract\xE8res, quels que soient leurs catcodes, est de faire pr\xE9c\xE9der le caract\xE8re de l'apostrophe inverse \emph{et} du caract\xE8re d'\xE9chappement comme dans cet exemple:
+
+\showcode/a) \number`\a \quad %code de caract\xE8re de "a"\xA4\idx*\number\idx*\quad\xA4
+b) \number`\\ \quad % code de caract\xE8re de "\"
+c) \number`\$ \quad % code de caract\xE8re de "$"
+d) \number`\  \quad % code de caract\xE8re de l'espace
+e) \number`\5 \quad % code de caract\xE8re de "5"
+f) \number`\{ \quad % code de caract\xE8re de l'accolade ouvrante
+g) \number`\}       % code de caract\xE8re de accolade fermante/
+
+Il devient facile d'afficher le code de cat\xE9gorie de n'importe quel caract\xE8re :
+
+\showcode/a) \number\catcode`\a \quad %code de cat\xE9gorie de "a"\xA4\idx*\catcode\xA4
+b) \number\catcode`\\ \quad % code de cat\xE9gorie de "\"\xA4\idx*\number\xA4
+c) \number\catcode`\$ \quad % code de cat\xE9gorie de "$"
+d) \number\catcode`\  \quad % code de cat\xE9gorie de l'espace
+e) \number\catcode`\5 \quad % code de cat\xE9gorie de "5"
+f) \number\catcode`\{ \quad % code de cat\xE9gorie de l'accolade ouvrante\xA4\idx*\quad\xA4
+g) \number\catcode`\}       % code de cat\xE9gorie de accolade fermante/
+
+Afficher un code de cat\xE9gorie n'est pas r\xE9ellement utile. Ce qui l'est plus est de \emph{modifier} le code de cat\xE9gorie d'un caract\xE8re, nous verrons dans quels buts plus loin. Pour ce faire, on \xE9crit\idx*{\catcode} :
+\centrecode-\catcode`\<caract\xE8re>=<nombre>-
+
+\noindent o\xF9 \verb-<nombre>- est un entier de 0 \xE0 15. Apr\xE8s que \TeX{} a ex\xE9cut\xE9 ce code, \xE0 chaque fois que \TeX{} lira le \verb-<caract\xE8re>-, il lui assignera le code de cat\xE9gorie \xE9gal au \verb-<nombre>-. Supposons par exemple que nous souhaitions que le caract\xE8re \xAB\verb|W|\xBB ne soit plus dans la cat\xE9gorie des lettres, mais rev\xEAte le code de cat\xE9gorie de 3 pour utiliser indiff\xE9remment \xAB\verb|W|\xBB ou \xAB\cidx\$\xBB pour basculer en mode math\xE9matique\idx*{mode!math\xE9matique}. Voici comment proc\xE9der :
+
+\showcode/Ici, W est une lettre...\par
+\catcode`\W=3 % W devient le signe de bascule en mode math\xA4\idx*\catcode\idx*{mode!math\xE9matique}\xA4
+Wx+y=3W\par
+$a+b=cW\par
+W2^3=8$\par
+\catcode`\W=11 % W redevient une lettre\xA4\idx*\catcode\xA4
+De nouveau, W est une lettre.../
+
+Il est important de restaurer le code de cat\xE9gorie initial \xE0 la fin de la zone o\xF9 l'on souhaite avoir le comportement voulu sous peine de s'exposer \xE0 des erreurs de compilation ou des effets ind\xE9sirables plus tard.
+
+Sym\xE9triquement, on aurait aussi bien pu assigner le code de cat\xE9gorie 11 (ou 12) au caract\xE8re \xAB\verb-$-\xBB de fa\xE7on \xE0 pouvoir l'afficher comme on le fait d'une lettre ou d'un caract\xE8re affichable :
+\showcode/$3+4=7$ \par % $ est la bascule math
+\catcode`\$=12 % $ devient un caract\xE8re affichable\xA4\idx*\catcode\xA4
+$ s'affiche sans probl\xE8me : $\par
+\catcode`\$=3 % $ redevient la bascule math\xA4\idx*\catcode\xA4
+$4+3=7$/
+
+\begin{exercice}
+Inventer un proc\xE9d\xE9 pour que, dans une zone, seuls les premiers mots de chaque ligne soient affich\xE9s.
+\solution
+Il suffit de modifier le code de cat\xE9gorie de l'\idx[!catcode 5]{espace} pour qu'il devienne 5. D'apr\xE8s la r\xE8gle vue \xE0 la page~\pageref{catcode.5}, dans une ligne, tout ce qui se trouve apr\xE8s un caract\xE8re de catcode 5\idx*{catcode!5 (retour charriot)} est ignor\xE9 :
+
+\showcode|Voici les premiers mots de chaque ligne :
+
+\catcode`\ =5 % l'espace est d\xE9ormais de catcode 5\xA4\idx*\catcode\xA4
+Cette premi\xE8re ligne sera tronqu\xE9e...
+
+La deuxi\xE8me aussi !
+
+Et la derni\xE8re \xE9galement.
+\catcode`\ =10 % l'espace reprend son catcode\xA4\idx*\catcode\xA4
+
+Le comportement normal est restaur\xE9.|
+\end{exercice}
+
+Il faut retenir que les codes de cat\xE9gorie attach\xE9s \xE0 chaque caract\xE8re de la table des catcodes de la page~\pageref{catcode.table} ne sont que des valeurs \emph{par d\xE9faut} qui peuvent \xEAtre facilement modifi\xE9es comme on l'a vu dans les exemples pr\xE9c\xE9dents. On peut donc parler de \xABr\xE9gime de catcode\xBB, c'est-\xE0-dire qu'\xE0 chaque moment, chacun des 256 octets aura un catcode qui lui sera attribu\xE9. En r\xE8gle g\xE9n\xE9rale, si l'on modifie le catcode d'un octet, il est sage de restaurer les codes de cat\xE9gorie de la table des catcodes au-del\xE0 de la zone o\xF9 l'on veut faire des modifications. En effet, il est admis que les catcodes \xABnaturels\xBB de cette table doivent rester la r\xE8gle.\idx*[|)]{catcode}\idx*[|)]{\catcode}
+%|                                                                            |
+%|                                Fin partie 1                                |
+%|____________________________________________________________________________|
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                                  Partie 2                                  |
+%|                                                                            |
+\defpartcomment{\lettrine[lines=3,nindent=0pt]{\libertineInitialGlyph{D}}{ans} cette partie, nous allons nous int\xE9resser \xE0 ce qui fait l'essentiel du code lorsqu'on programme, les commandes. Contrairement \xE0 d'autres langages de programmation o\xF9 leur comportement est assez intuitif, elles rev\xEAtent avec \TeX{} des propri\xE9t\xE9s originales. Par leur interm\xE9diaire, nous d\xE9couvrirons l'essentiel de ce qu'il faut savoir pour commencer \xE0 programmer c'est-\xE0-dire la fa\xE7on intrins\xE8que qu'a \TeX{} de fonctionner et comment contr\xF4ler ce fonctionnement. Apr\xE8s ces pr\xE9requis, nous pourrons alors aborder la partie suivante o\xF9 nous commencerons les premiers exercices de programmation.}
+\part{Commandes}
+
+\chapter[\Qu 'est-ce qu'une commande ?]{Qu'est-ce qu'une commande ?}
+Lorsqu'on utilise \TeX{}, les s\xE9quences de contr\xF4le\idx*{s\xE9quence de contr\xF4le} sont des mots constitu\xE9s de lettres (caract\xE8res de catcode 11) qui d\xE9butent par le \idx{caract\xE8re d'\xE9chappement} \xAB\cidx[ (caract\xE8re d'\xE9chappement)]\\\xBB. Ce caract\xE8re sp\xE9cial peut \xEAtre chang\xE9 pour en utiliser un autre, mais cette man\-\oe uvre ne sera pas d\xE9crite pour l'instant. Ainsi, lorsque \TeX{} lit le code que l'on a tap\xE9, toujours lin\xE9airement de gauche \xE0 droite, forme une \idx{s\xE9quence de contr\xF4le} \xE0 l'aide des lettres, majuscules ou minuscules, qui suivent le caract\xE8re d'\xE9chappement \xAB\cidx\\\xBB, la casse \xE9tant prise en compte. \TeX{} consid\xE8re que le nom de la \idx{s\xE9quence de contr\xF4le} se termine au dernier caract\xE8re qui est une lettre . Une fois que ce nom est construit, il devient une entit\xE9 unitaire indivisible, une \xABunit\xE9 lexicale\xBB ou \xAB\emph{\idx{token}}\xBB au m\xEAme titre qu'un \idx{octet} dans le code si celui-ci ne sert pas \xE0 \xE9crire une \idx{s\xE9quence de contr\xF4le}.
+
+\begin{regle}
+Une \idx{s\xE9quence de contr\xF4le} commence par le caract\xE8re d'\xE9chappement de catcode 0\idx*{catcode!0 (caract\xE8re d'\xE9chappement)} qui est habituellement \xAB\cidx\\\xBB et se termine \xE0 la fin de la plus longue s\xE9rie de lettres (caract\xE8res de catcode 11\idx*{catcode!11 (lettre)}) qui le suit.
+\end{regle}
+
+Les s\xE9quences de contr\xF4le sont de deux types :
+\begin{itemize}
+	\item les \xABcommandes\xBB, que l'on appellera aussi \xABmacros\xBB, ont \xE9t\xE9 d\xE9finies soit par l'utilisateur, par un format ou par une extension. Ces commandes ont un \idx{texte de remplacement}, c'est le code \TeX{} qui les d\xE9finit, ou si l'on pr\xE9f\xE8re, le code \TeX{} qu'elles \xABcontiennent\xBB. Ce texte de remplacement peut \xE9videmment contenir d'autres s\xE9quences de contr\xF4le ;
+	\item les \idx{primitive}s, qui sont cod\xE9es en dur dans le programme binaire \texttt{tex}, et qui repr\xE9sentent en fait le \xABvocabulaire\xBB de base avec lequel on doit se d\xE9brouiller pour faire tout le reste. Les primitives n'ont pas de \idx{texte de remplacement} et sont destin\xE9es \xE0 \xEAtre ex\xE9cut\xE9es de fa\xE7on binaire par le programme \texttt{tex}.
+\end{itemize}
+
+\label{regle.espace}\begin{regle}
+Voici des r\xE8gles concernant les espaces et les s\xE9quences de contr\xF4le :
+	\begin{enumerate}
+		\item dans le code qui est tap\xE9, tout \idx{espace} qui suit une unit\xE9 lexicale de type \idx{s\xE9quence de contr\xF4le} est ignor\xE9;
+		\item si plusieurs espaces \idx*{espace!cons\xE9cutifs}se suivent \emph{dans le code}, seul le premier est pris en compte et les autres sont ignor\xE9s (ceci est un rappel de la r\xE8gle page~\pageref{espaces.consecutifs});
+		\item il d\xE9coule des deux premiers points que, quel que soit le nombre d'espaces qui suivent une \idx{s\xE9quence de contr\xF4le}, ceux-ci sont ignor\xE9s.
+	\end{enumerate}
+\end{regle}
+
+Lorsqu'un utilisateur d\xE9finit une commande, il lui donne un \emph{\idx{texte de remplacement}} qui sera utilis\xE9 \xE0 la place de cette commande lorsqu'elle sera \xAB ex\xE9cut\xE9e \xBB par \TeX{}. La primitive qui permet de d\xE9finir ce texte de remplacement est \xAB\idx[|(]\def\xBB. Elle doit \xEAtre suivie du nom de la commande et du texte de remplacement entre \idx{accolade}s :
+
+\centrecode-\def\foo{Bonjour}-
+
+Apr\xE8s cette d\xE9finition, \xE0 chaque fois que \TeX{} \xABex\xE9cutera\xBB le token \verb|\foo| dans le code source, il le remplacera dans sa m\xE9moire par son texte de remplacement qui est \xABBonjour\xBB et continuera \xE0 lire le code obtenu en tenant compte de ce remplacement. Cet endroit dans sa m\xE9moire s'appelle \xAB\idx{pile d'entr\xE9e}\xBB. Pour \xE9crire un espace apr\xE8s \verb-\foo- qui ne soit pas ignor\xE9, il faut trouver un moyen, invisible \xE0 l'affichage, pour que l'espace affich\xE9 apr\xE8s la macro ne lui soit pas cons\xE9cutif. On peut envelopper la macro dans des accolades ou la faire suivre de \verb-{}-\cidx*\{\cidx*\} de fa\xE7on \xE0 ce que l'espace se situant \emph{apr\xE8s} l'accolade fermante ne soit pas ignor\xE9 comme il le serait apr\xE8s une \idx{s\xE9quence de contr\xF4le}. On peut \xE9galement mettre apr\xE8s \verb|\foo| la macro \idx\space dont le \idx{texte de remplacement} est un espace. Dans ce cas, le dernier point de la r\xE8gle pr\xE9c\xE9dente ne s'applique pas, car ce qui suit \verb|\foo| n'est pas un espace mais une \idx{s\xE9quence de contr\xF4le}, et peu importe son texte de remplacement.
+
+\showcode/\def\foo{Bonjour}% d\xE9finit le texte de remplacement de \foo
+a) \foo Alice.\qquad% espace ignor\xE9\xA4\idx*\qquad\xA4
+b) {\foo} Bob.\qquad% espace non ignor\xE9
+c) \foo{} Chris.\qquad% espace non ignor\xE9
+d) \foo\space Daniel.% \space est remplac\xE9 par un espace\xA4\idx*\space\xA4/
+
+\begin{regle}
+Lorsque \TeX{} assigne un \idx{texte de remplacement} \xE0 une macro avec \idx\def, ce texte de remplacement n'est pas ex\xE9cut\xE9, il est juste converti en \idx{token}s et rang\xE9 quelque part dans la m\xE9moire de \TeX{} pour \xEAtre ressorti plus tard pour venir en replacement de la macro, et \xE9ventuellement \xEAtre ex\xE9cut\xE9 \xE0 ce moment.
+
+Le texte de remplacement est tr\xE8s peu \emph{analys\xE9} lorsqu'il est stock\xE9 avec \verb|\def|, ce qui veut dire que si une erreur est contenue dans le texte de remplacement, elle ne sera pas d\xE9tect\xE9e au moment o\xF9 \idx\def agit mais plus tard lors du remplacement et de l'ex\xE9cution proprement dite.
+
+Une des rares choses que \TeX{} v\xE9rifie dans le \idx{texte de remplacement} d'une macro est qu'un caract\xE8re de \idx*[!15 (invalide)]{\catcode}catcode 15\idx*{catcode!15 (invalide)} n'y figure pas (nous verrons plus loin les autres v\xE9rifications que \TeX{} effectue).
+\end{regle}
+
+\section{Accolades et groupes}
+Les \cidx*\{\cidx*\{\idx{accolade}s des lignes 3 et 4 d\xE9limitent des \xAB\idx[|(]{groupe}s\footnote{On dit aussi parfois \xAB\idx[!simple]{groupe} simple\xBB.}\xBB. Un groupe est une zone o\xF9 les modifications effectu\xE9es et o\xF9 les d\xE9finitions faites restent \emph{locales} \xE0 ce groupe et sont d\xE9truites lors de sa fermeture pour revenir \xE0 l'\xE9tat ant\xE9rieur \xE0 l'ouverture du groupe. En revanche, les \idx{accolade}s obligatoires utilis\xE9es avec la primitive \idx\def de la ligne 1 ne d\xE9limitent pas un groupe. Elles d\xE9limitent la port\xE9e du \idx{texte de remplacement}. On peut donc consid\xE9rer qu'il y a deux types d'\idx{accolade}s. D'une part celles qui sont obligatoires et font partie de la syntaxe d'une primitive comme celles de la primitive \idx\def qui d\xE9limitent le \idx{texte de remplacement} et d'autre part celles, non obligatoires, qui servent de fronti\xE8res \xE0 un groupe.
+
+Un \idx[!semi-simple]{groupe} semi-simple\footnote{Le nom \xAB groupe simple \xBB \xE9tant d\xE9j\xE0 pris pour les groupes entre accolades, il y a fort \xE0 parier que D.~\textsc{Knuth}, par jeu et par affinit\xE9 pour les math\xE9matiques, ait baptis\xE9 \xAB groupe semi-simple\xBB un groupe d\xE9limit\xE9 par \texttt{\textbackslash begingroup} et \texttt{\textbackslash endgroup}.} est compris entre les instants o\xF9 \TeX{} ex\xE9cute les primitives \idx\begingroup et \idx\endgroup. Comme dans les groupes, les modifications et les d\xE9finitions dans un groupe semi-simple sont locales et sont restaur\xE9es \xE0 leur \xE9tat ant\xE9rieur \xE0 sa fermeture.
+
+\begin{regle}
+On peut cr\xE9er des zones o\xF9 les modifications faites aux macros et autres param\xE8tres de \TeX{} sont locales. Ces zones portent le nom de \idx{groupe}s.
+
+Un \idx{groupe} est d\xE9limit\xE9 :
+\begin{itemize}
+	\item soit par une \idx{accolade} ouvrante et une accolade fermante auquel cas le groupe est qualifi\xE9 de \xAB simple \xBB ;
+	\item soit par les primitives \idx\begingroup et \idx\endgroup et dans ce cas, le groupe est dit \xAB semi-simple\xBB.
+\end{itemize}
+Il est entendu qu'un groupe ouvert avec une accolade ne peut \xEAtre ferm\xE9 qu'avec une accolade et il en est de m\xEAme avec \idx\begingroup et \idx\endgroup.
+
+\xC0 l'int\xE9rieur d'un groupe, les assignations sont locales \xE0 ce groupe et sont restaur\xE9es \xE0 leur \xE9tat ant\xE9rieur lors de la fermeture du groupe. Pour qu'une assignation soit \emph{globale}, c'est-\xE0-dire pour qu'elle survive \xE0 la fermeture du groupe, il faut faire pr\xE9c\xE9der la commande d'assignation de la primitive \idx\global.
+
+Les groupes d\xE9limit\xE9s par accolades et les groupes semi-simples peuvent \xEAtre emboit\xE9s, mais \emph{ne doivent pas} se chevaucher.
+\end{regle}
+
+\begin{exercice}
+Puisqu'un groupe d\xE9limit\xE9 par accolades et un groupe semi-simple ont les m\xEAmes fonctionnalit\xE9s, pourquoi existe-t-il deux fa\xE7ons diff\xE9rentes de d\xE9limiter un groupe ?
+\solution
+Tout d'abord, abondance de biens ne nuit pas !
+
+Ensuite, il y a des cas o\xF9 une \idx{accolade} ne peut pas d\xE9limiter un d\xE9but ou une fin groupe, c'est dans le texte de remplacement d'une macro. Par exemple, si l'on voulait qu'une macro \verb|\startbold| ouvre un groupe et \xE9crive en gras et que la macro \verb|\stopbold| stoppe ce fonctionnement, on serait oblig\xE9 d'utiliser \idx\begingroup et \idx\endgroup :
+
+\showcode|\def\startbold{\begingroup \bf}
+\def\stopbold{\endgroup}
+Voici \startbold du texte en gras\stopbold{} et la suite.|
+
+En effet, cela constituerait une erreur que d'\xE9crire :
+
+\centrecode|\def\startbold{{\bf}
+\def\stopbold{}}|
+
+\noindent car le texte de remplacement de \verb|\startbold| irait jusqu'\xE0 la prochaine accolade \xE9quilibr\xE9e et serait
+
+\centrecode|{\bf} \def\stopbold{}|
+
+\noindent Il n'y aurait pas d'erreur de compilation, mais la port\xE9e de \verb|\bf| serait nulle puisque cette macro est seule dans son groupe et \verb|\stopbold|, ayant un texte de remplacement vide, n'aurait aucune action.
+\end{exercice}
+
+\begin{exercice}
+D\xE9crire ce qui se passe exactement et quel va \xEAtre l'affichage si l'on d\xE9finit une macro \verb|\foo| dans ce contexte :
+
+\centrecode-\begingroup
+\def\foo{Hello \endgroup world !}
+\foo-
+
+\solution
+D\xE9j\xE0, la d\xE9finition sera \emph{locale} au groupe semi-simple initi\xE9 par \idx\begingroup et la macro \verb|\foo| sera d\xE9truite d\xE8s qu'un \idx\endgroup sera ex\xE9cut\xE9 pour revenir \xE0 ce qu'elle \xE9tait avant le groupe semi-simple (\xE9ventuellement ind\xE9finie). Le \idx\endgroup de la ligne 2 n'est pas \xABex\xE9cut\xE9\xBB par \TeX{} puisque ce \idx\endgroup est stock\xE9 dans le \idx{texte de remplacement} de la macro \verb|\foo|. Il ne ferme donc pas le groupe semi-simple lorsque \TeX {} ex\xE9cute la ligne \no2 du code.
+
+Lorsque \TeX{} rencontre \verb|\foo| \xE0 la 3\ieme{} ligne du code, il se trouve toujours dans le groupe semi-simple ouvert par \idx\begingroup et la d\xE9finition faite la ligne au-dessus est toujours en vigueur. \TeX{} remplace donc \verb|\foo| par son texte de remplacement, ce remplacement se faisant dans la \idx{pile d'entr\xE9e} de \TeX{} :
+
+\centrecode-Hello \endgroup world !-
+
+\noindent \TeX{} va continuer \xE0 lire ce qu'il y a dans sa pile et va donc afficher \verb*|Hello | puis, en rencontrant \idx\endgroup, d\xE9truira la d\xE9finition locale de \verb|\foo| enfin continuera \xE0 lire ce qui est dans sa pile et affichera : \verb|world !|.
+
+On voit donc que dans ce cas, la macro \verb|\foo| porte dans son \idx{texte de remplacement} la primitive \idx\endgroup qui provoquera son autodestruction !\idx*[|)]{groupe}\idx*[|)]\def
+\end{exercice}
+
+\begin{regle}
+La primitive \idx\aftergroup\verb|<token>| permet de stocker un \verb|<token>| dans une pile sp\xE9ciale de la m\xE9moire de \TeX pour que ce \idx{token} soit lu et ex\xE9cut\xE9 juste apr\xE8s \xEAtre sorti du groupe courant, que ce groupe soit simple ou semi-simple.
+
+Si plusieurs commandes \idx\aftergroup sont rencontr\xE9es dans un m\xEAme groupe, les \idx{token}s mis en m\xE9moire seront lus dans l'ordre o\xF9 ils ont \xE9t\xE9 d\xE9finis. Ainsi, \xE9crire
+
+\centrecode-\aftergroup<x>\aftergroup<y>-\idx*\aftergroup
+
+se traduira par \xAB\verb|<x><y>|\xBB apr\xE8s la fermeture du groupe.
+\end{regle}
+
+\showcode/\def\foo{foo}
+\begingroup A\aftergroup\foo B\endgroup\par
+{A\aftergroup X\aftergroup\foo B}/
+
+La primitive \idx\aftergroup trouve une utilit\xE9 lorsque la composition en italique est demand\xE9e dans un groupe (qui en d\xE9limite la port\xE9e). En effet, pour \xE9viter que le dernier caract\xE8re en italique (qui est donc pench\xE9 vers la droite) ne soit trop pr\xE8s du caract\xE8re du mot suivant (qui est vertical), il convient d'ins\xE9rer \xE0 la fin du groupe une \idx{correction d'italique}, surtout si les deux caract\xE8res sont des lettres hautes comme \xABl\xBB, \xABf\xBB ou une parenth\xE8se fermante. Cette correction, effectu\xE9e en \TeX{} par la primitive \idx[ (correction d'italique)]\/, augmente l\xE9g\xE8rement l'espace entre ces deux caract\xE8res. La diff\xE9rence est tr\xE8s fine, mais elle existe :
+
+\showcode|1) (un {\it cheval})\par% sans correction d'italique\xA4\idx*\it\xA4
+2) (un {\it\aftergroup\/cheval})\par% avec correction d'italique\xA4\idx*[ (correction d'italique)]\/\idx*\aftergroup\idx*\it\xA4
+% on peut d\xE9finir une macro \itacorr qui effectue automatiquement la correction
+\def\itacorr{\it\aftergroup\/}\xA4\idx*\aftergroup\xA4
+3) (un {\itacorr cheval})% avec correction d'italique|
+
+\section{Primitive \ttfamily{\textbackslash let}}\label{let}
+\idx*[|(]{\let}Pour copier le \idx[!copie]{texte de remplacement} d'une macro vers une autre, on utilise la primitive \verb-\let- qui prend comme arguments deux unit\xE9s lexicales de type \idx{s\xE9quence de contr\xF4le}. Par exemple, \xE9crire \verb-\let\foo=\bar- copiera le texte de remplacement de la macro \verb-\bar- vers \verb-\foo- en \xE9crasant celui de cette derni\xE8re si elle \xE9tait d\xE9j\xE0 d\xE9finie. Le signe \xAB=\xBB entre les deux s\xE9quences de contr\xF4le est facultatif et sera souvent omis d\xE9sormais\footnote{En r\xE9alit\xE9, le signe \xE9gal peut aussi \xEAtre suivi d'\emph{un} espace facultatif.}. Une fois cette copie faite, peu importe ce que sera le futur de \verb-\bar-, la copie a lieu \xE0 l'instant o\xF9 \verb-\let- est rencontr\xE9 et si \verb-\bar- est red\xE9finie par la suite, cela n'affectera pas le texte de remplacement de \verb-\foo-.
+
+\showcode/\def\bar{Je suis bar.}
+\let\foo\bar % \foo devient \xE9gal \xE0 \bar
+\def\bar{ABC}% \bar est red\xE9finie
+\foo\par% affiche "Je suis bar"
+\bar% affiche "ABC"/
+
+Lorsqu'on \xE9crit \verb-\let\foo=\bar-, si \verb-\bar- est une primitive, alors \verb-\foo- devient un \emph{alias} pour cette primitive et pour \TeX{}, elles sont identiques. Il est important de noter que ni \idx\def ni \verb-\let- ne pr\xE9viennent d'aucune fa\xE7on l'utilisateur qu'il \xE9crase une \idx{s\xE9quence de contr\xF4le} et que sa d\xE9finition pr\xE9c\xE9dente sera perdue. Et tant pis si c'est une primitive. Si par malheur on \xE9crit \verb-\let\def\foo-, alors, \xE0 partir de ce moment, la primitive \verb-\def- sera \xE9cras\xE9e et il ne sera donc plus possible de d\xE9finir de commande.
+\begin{exercice}
+\Qu e fait le code suivant : \verb-\let\foo\let\foo\bar\foo- ?
+\solution
+En proc\xE9dant comme \TeX{} et en ne lisant que ce dont on a besoin, on a d'abord \verb-\let\foo\let- et donc \verb-\foo- devient \xE9gale \xE0 la primitive \verb-\let-.
+
+Ensuite, on a \verb-\foo\bar\foo- mais comme \verb-\foo- est devenue un alias de \verb-\let-, tout se passe comme si l'on \xE9crivait \verb-\let\bar\let- et donc, \verb-\bar- devient aussi \xE9gale \xE0 \verb-\let-.
+
+Le code rend donc \verb-\foo- et \verb-\bar- \xE9gales \xE0 \verb-\let-.
+\end{exercice}
+
+La commande \verb-\let- peut aussi \xEAtre utilis\xE9e pour d\xE9finir des \xABcaract\xE8res implicites\idx*{caract\xE8re implicite}\xBB. La syntaxe ne change pas, mais au lieu de la seconde \idx{s\xE9quence de contr\xF4le}, on met un caract\xE8re. Si on \xE9crit par exemple \verb-\let\foo=a-, la \idx{s\xE9quence de contr\xF4le} \verb-\foo- devient un \xAB\texttt a implicite\xBB. Cela signifie qu'elle produira un \xAB\texttt a\xBB \xE0 l'affichage et que lorsque \TeX{} teste cette \idx{s\xE9quence de contr\xF4le} (nous verrons comment plus tard), il la voit \xE9gale \xE0 \xAB\texttt a\xBB. Il est bien \xE9vident que \verb-\foo- ne peut pas \xEAtre utilis\xE9e \xE0 la place de \xAB\texttt a\xBB n'importe o\xF9 dans le code. Si on veut \xE9crire \verb-\par-, on ne peut pas \xE9crire \verb-\p\foo r- !
+
+La d\xE9finition d'un caract\xE8re implicite via \verb|\let| ne peut se faire que pour les caract\xE8res \emph{inoffensifs} que l'on peut rencontrer, c'est-\xE0-dire ayant un catcode 11\idx*{catcode!11 (lettre)} ou 12\idx*{catcode!12 (autre)}, ainsi que pour ceux ayant le catcode 1\idx*{catcode!1 (accolade)}, 2, 3, 4, 6, 7, 8. Il est par exemple impossible de d\xE9finir un \xAB\verb|%|\xBB ou un \xAB\verb|\|\xBB implicite avec \verb|\let|. Pour l'espace, cela requiert un plus haut niveau de \TeX nicit\xE9 que nous verrons plus loin (page~\pageref{sptoken}).
+
+Pour les \idx[!implicite]{accolade}s ouvrantes et fermantes (dont les catcodes sont respectivement 1\idx*{catcode!1 (accolade)} et 2), il existe des tokens implicites\idx*[!implicite]{token} pr\xE9d\xE9finis tr\xE8s importants qui sont \idx\bgroup et \idx\egroup. Ils sont d\xE9finis par plain-\TeX{} de la fa\xE7on suivante :
+
+\begin{centrage}
+\small\verb-\let\bgroup={-\kern2cm\verb-\let\egroup=}-
+\end{centrage}
+
+\noindent Ces \emph{\idx[!implicite]{accolade}s implicites} peuvent jouer le m\xEAme r\xF4le de d\xE9limiteur de groupe que les accolades explicites \xAB\verb-{-\xBB\cidx*\{ et \xAB\verb-}-\xBB\cidx*\{ mais dans la grande majorit\xE9 des cas, elles ne sont \emph{pas} interchangeables avec les accolades explicites. Par exemple, elles ne peuvent pas \xEAtre utilis\xE9es pour dans la syntaxe de \idx\def pour d\xE9limiter le texte de remplacement d'une macro.
+\grandsaut
+
+\xC0 ce stade, on peut donc faire un point \TeX nique sur tout ce qui sert \xE0 d\xE9limiter un \idx{groupe} \xE0 savoir :
+\begin{itemize}
+	\item la paire \idx\begingroup\linebreak[1]\verb|...|\linebreak[1]\idx\endgroup;
+	\item les accolades explicites \xAB\cidx\{\xBB et \xAB\cidx\}\xBB ;
+	\item les accolades implicites \idx\bgroup\linebreak[1]\verb|...|\linebreak[1]\idx\egroup.
+\end{itemize}
+
+Tout d'abord, un \idx{groupe} ouvert par \idx\begingroup ne peut \xEAtre referm\xE9 que par \idx\endgroup et donc, le \idx[!semi-simple]{groupe} semi-simple est totalement ind\xE9pendant du groupe ouvert par des accolades. Les choses sont diff\xE9rentes pour les groupes ouverts et ferm\xE9s par \xAB\cidx\{\xBB et \xAB\cidx\}\xBB ou par \xAB\idx\bgroup\xBB et \xAB\idx\egroup\xBB. Tout d'abord, s'il n'existe aucune contrainte d'\xE9quilibrage d'accolades, \xAB\cidx\{\xBB et \idx\bgroup sont interchangeables pour ouvrir un groupe et \xAB\cidx\}\xBB et \idx\egroup le sont pour le fermer. Enfin, il y a quelques \emph{rares} primitives o\xF9 les accolades explicites et implicites sont interchangeables dans leur syntaxe :
+
+\begin{itemize}
+	\item les primitives \idx\hbox, \idx\vbox et \idx\vtop attendent apr\xE8s elles un texte entre accolades pour le composer dans une boite (pour en savoir plus, voir la section \ref{boites} page~\pageref{boites} et suivantes).
+
+	Ce sont les seules primitives o\xF9 l'on peut indiff\xE9remment utiliser des accolades explicites ou implicites, aussi bien pour ouvrir que pour fermer. Par cons\xE9quent, \xAB\verb|\hbox{a}|\xBB et \xAB\verb|\hbox\bgoup| \verb|a\egroup|\xBB sont \xE9quivalents;
+	\item certaines primitives que nous verrons et utiliserons plus loin ont une propri\xE9t\xE9 encore plus curieuse\ldots{}
+	
+	Ces primitives doivent \xEAtre imm\xE9diatement suivies d'une accolade ouvrante. Les plus connues sont \idx\toks\verb|<nombre>|, \idx\lowercase, \idx\uppercase et pour celles de \idx\eTeX{}, \idx\detokenize et \idx\unexpanded. Elles tol\xE8rent indiff\xE9remment \xAB\verb|{|\xBB ou \xAB\idx\bgroup\xBB pour l'accolade ouvrante. En revanche, l'accolade fermante \emph{doit} \xEAtre une accolade explicite.
+
+	Ainsi, \xAB\idx\lowercase\verb|{Foo}|\xBB et \xAB\idx\lowercase\verb|\bgroup Foo}|\xBB sont accept\xE9s et sont \xE9quivalents.
+\end{itemize}
+
+\begin{exercice}
+Si l'on \xE9crit le code ci-dessous, va-t-on obtenir \xAB$a^3=b_5$\xBB ?
+
+\centrecode|\let\swichmath=$ \let\expo= ^ \let\ind _ \let\egal= =
+\swichmath a\expo3\egal b\ind5$|
+
+\solution
+Oui car tous les tokens implicites\idx*[!implicite]{token} d\xE9finis ici le sont avec la bonne syntaxe (le signe \verb-=- et l'espace facultatif qui le suit sont pr\xE9sents ou pas) et surtout, les catcodes des tokens implicites permettent une telle d\xE9finition.
+\end{exercice}
+
+\begin{exercice}
+\Qu e va t-il se passer si l'on d\xE9finit la macro \verb-\foo- ainsi : \verb-\let\foo={hello}-
+\solution
+\TeX{} va d'abord lire \verb-\let\foo={- et donc, \verb-\foo- va devenir une accolade implicite.
+
+Ensuite, le reste du code \xE0 lire est \xAB\verb-hello}-\xBB. Tout va bien se passer jusqu'\xE0 l'accolade fermante. La premi\xE8re accolade ouvrante ayant \xE9t\xE9 lue et absorb\xE9e par le \verb-\let-, celle-ci n'a pas \xE9t\xE9 prise en compte dans le comptage interne \xE0 \TeX{} concernant l'\xE9quilibrage des accolades, l'accolade fermante devient orpheline et \TeX{} va nous gratifier d'un \xAB\verb-Too many }'s-\xBB. Cette derni\xE8re erreur ne surviendra pas si auparavant, une accolade $x$ a \xE9t\xE9 ouverte sans encore \xEAtre ferm\xE9e par une accolade fermante; dans ce cas, l'accolade qui suit \xAB\verb|hello| \xE9quilibrera l'accolade $x$ ouverte pr\xE9alablement \xE0 ce code.
+
+Pour \emph{d\xE9finir} une macro et lui donner un texte de remplacement, on ne doit utiliser que \idx\def puis le nom de la macro puis le texte de remplacement entre accolades.
+\end{exercice}
+
+La primitive \verb-\let- est parfois utile pour faire une sauvegarde d'une commande de fa\xE7on \xE0 pouvoir la restaurer \xE0 son \xE9tat initial apr\xE8s y avoir apport\xE9 des modifications. Prenons un mauvais exemple et d\xE9cidons de modifier la macro \verb-\TeX- pour qu'elle n'affiche plus \xAB\TeX\xBB mais \xABtEx\xBB. Nous allons d'abord d\xE9finir avec \verb-\let- un alias de \verb-\TeX- que nous appelons \verb-\TeXsauve- puis nous pourrons modifier la commande \verb-\TeX- et utiliser cette commande avec sa nouvelle d\xE9finition. \xC0 la fin, avec \verb-\let- \xE0 nouveau, nous la restaurerons pour revenir au comportement initial :
+
+\showcode/Initialement, c'est \TeX.\par
+\let\TeXsauve\TeX% sauvegarde
+\def\TeX{tEx}% red\xE9finition
+Ici, on a modifi\xE9 \TeX.\par
+\let\TeX\TeXsauve% retauration
+De nouveau, c'est \TeX./\idx*[|)]{\let}
+
+\section{Les primitives \texttt{\textbackslash csname} et \texttt{\textbackslash endcsname}}\idx*[|(]\csname\idx*[|(]\endcsname
+Pour \xE9crire une \idx{s\xE9quence de contr\xF4le}, on peut bien s\xFBr faire pr\xE9c\xE9der son nom du caract\xE8re \xAB\verb|\|\xBB, c'est que nous avons fait jusqu'ici\ldots{} Mais il y a une autre m\xE9thode pour cr\xE9er une \idx{s\xE9quence de contr\xF4le}. On peut utiliser la paire de primitives \verb-\csname- et \verb-\endcsname- qui utilisent les caract\xE8res qui se trouvent entre elles pour les convertir en \idx{s\xE9quence de contr\xF4le}. Par exemple, si \TeX{} rencontre \verb-\csname-\linebreak[1]\verb*- foo-\linebreak[1]\verb-\endcsname-\footnote{L'espace qui suit \texttt{\string\csname} est ignor\xE9 en vertu de la r\xE8gle vue \xE0 la page~\pageref{regle.espace}}, dans un premier temps il construira l'unit\xE9 lexicale \xAB\verb|\foo|\xBB et dans un deuxi\xE8me temps, il lui substituera son texte de remplacement, tout ceci \xE9tant effectu\xE9 dans la m\xE9moire de \TeX{}, dans la \idx{pile d'entr\xE9e}. \xC0 l'affichage, l'effet est le m\xEAme que si l'on avait directement \xE9crit \verb-\foo-, mais dans les entrailles de \TeX{}, il y a une \xE9tape de plus, celle de former la \idx{s\xE9quence de contr\xF4le} avec ce qui se trouve entre \verb-\csname- et \verb-\endcsname-. L'avantage de cette m\xE9thode est que l'on peut utiliser des caract\xE8res normalement interdits dans le nom de commandes, c'est-\xE0-dire des tokens dont le catcode est diff\xE9rent de 11, celui des lettres. On peut donc construire des s\xE9quences de contr\xF4le dont le nom comporte des espaces, des chiffres, des signes d'op\xE9rations, de ponctuation ainsi que d'autres caract\xE8res r\xE9serv\xE9s dont les codes de cat\xE9gorie sont sp\xE9ciaux (\verb|&|, \verb|#|, \verb|^|, \verb|_|, \verb|$|).
+
+Un autre avantage non n\xE9gligeable est que si jamais la \idx{s\xE9quence de contr\xF4le} form\xE9e par \verb-\csname-\ldots\verb-\endcsname- n'est pas d\xE9finie, \TeX{} la rend \xE9gale \xE0 \idx\relax qui est une primitive dont l'action est de ne rien faire. Ainsi, \xE9crire \verb-\foobar- dans le code alors que cette macro n'a pas \xE9t\xE9 d\xE9finie par \idx\def ou \idx\let provoquera une erreur de compilation \xAB\texttt{Undefined control sequence}\xBB. En revanche, \xE9crire \verb-\csname foobar\endcsname- revient \xE0 invoquer la primitive \idx\relax et il ne se passera donc rien.
+
+Le revers de la m\xE9daille est que, pour \TeX{}, former une \idx{s\xE9quence de contr\xF4le} avec \verb-\csname-\ldots\verb-\endcsname- est \emph{beaucoup} plus lent que de l'\xE9crire directement avec le caract\xE8re d'\xE9chappement. Si c'est possible, il vaut donc mieux \xE9viter d'utiliser cette m\xE9thode dans les boucles des programmes.
+
+\begin{exercice}
+Apr\xE8s avoir d\xE9fini la macro \verb-\foo- avec \verb-\def\foo{Bonjour}-, pourquoi rien ne s'affiche lorsqu'on \xE9crit \xAB\verb-\csname foo \endcsname-\xBB?
+\solution
+Parce que l'espace qui suit le \xABfoo\xBB est pris en compte pour construire le nom de la \idx{s\xE9quence de contr\xF4le}. Ainsi, \xE9crire \verb-\csname-\linebreak[1]\verb*- foo -\linebreak[1]\verb-\endcsname- construit la commande {\fboxsep0.3pt\fbox{\ttfamily\textbackslash foo\textvisiblespace}} qu'il serait fastidieux de construire autrement. Celle-ci \xE9tant ind\xE9finie, la construire avec  \verb-\csname-\ldots\verb-\endcsname- la rend \xE9gale \xE0 \idx\relax et il ne se passe donc rien.
+\end{exercice}
+\begin{exercice}
+\label{non.dev.csname}Pourquoi \xE9crire \idx\let\verb-\salut\csname foo\endcsname- pour rendre \xE9gale \verb|\salut| \xE0 \verb|\foo| provoque une erreur de compilation ?
+\solution
+L'erreur survient parce que \TeX{} lit le code de gauche \xE0 droite en prenant en compte uniquement ce dont il a besoin. Il lit donc d'abord \idx\let\verb-\salut\csname-. Ce faisant, il rend donc la commande \verb-\salut- \xE9gale \xE0 \verb-\csname-. Ayant effectu\xE9 cette op\xE9ration, il poursuit avec la suite du code qui est \verb-foo\endcsname-. Les lettres \xABfoo\xBB ne vont pas lui poser de probl\xE8me, il les affichera normalement, mais il va rencontrer la commande \verb-\endcsname- sans avoir rencontr\xE9 le \verb-\csname- qui initiait le d\xE9but de la construction du nom de la commande. Il va donc \xE9mettre le message d'erreur \xAB\texttt{Extra \string\endcsname}\xBB.
+
+Pour faire ce que nous voulions, il faudrait forcer \TeX{} \xE0 construire la \idx{s\xE9quence de contr\xF4le} \verb|\foo| \xE0 partir de \verb*-\csname -\linebreak[1]\verb- foo-\linebreak[1]\verb-\endcsname- avant qu'il ne passe la main \xE0 \verb-\let-. Pour provoquer cette action, il faudrait sauter les deux tokens \verb-\let\salut- pour provoquer cette action et revenir o\xF9 l'on \xE9tait avant les sauts pour reprendre la lecture du code dans l'ordre normal. Pour effectuer cette man\-\oe uvre non lin\xE9aire qui d\xE9roge \xE0 la r\xE8gle de lecture du code, il faut avoir recours \xE0 la primitive \idx\expandafter que nous verrons plus loin.
+\end{exercice}
+\begin{exercice}
+On a vu comment d\xE9finir une commande avec \idx\def. Existe-t-il un moyen d'annuler une d\xE9finition et faire qu'une commande pr\xE9alablement d\xE9finie redevienne ind\xE9finie ?
+\solution
+Il n'existe pas de primitive \verb-\undef- qui rendrait une commande ind\xE9finie \emph{et} l'enl\xE8verait de la table de hashage\footnote{Il s'agit d'une structure interne \xE0 \TeX{} o\xF9 sont stock\xE9s les appariements entre les noms des macros et l'endroit de la m\xE9moire o\xF9 sont stock\xE9s leurs textes de remplacement.}.
+
+On peut cependant combler ce manque. En effet, si l'on d\xE9finit une commande \xE0 l'int\xE9rieur d'un \idx{groupe} simple ou semi-simple, la d\xE9finition est locale au groupe et est perdue \xE0 sa fermeture. Par cons\xE9quent, si la commande \xE9tait ind\xE9finie avant l'ouverture du groupe, elle le redevient apr\xE8s sa fermeture.
+
+Si l'on souhaite d\xE9finir une commande de fa\xE7on globale, la primitive \idx\global, lorsqu'elle est plac\xE9e devant une assignation, rend cette assignation globale c'est-\xE0-dire qu'elle survit \xE0 la fermeture du groupe. La primitive \idx\gdef se comporte comme \idx\global\verb|\def|.
+\end{exercice}\idx*[|)]\csname\idx*[|)]\endcsname
+
+\section{Caract\xE8re de contr\xF4le}\idx*[|(]{caract\xE8re de contr\xF4le}
+
+\begin{regle}
+Lorsque le caract\xE8re d'\xE9chappement \xAB\cidx\\\xBB est suivi d'un caract\xE8re dont le catcode n'est pas 11\idx*{catcode!11 (lettre)}, celui des lettres, seul ce caract\xE8re est pris en compte et \TeX{} forme ce que l'on appelle un \xABcaract\xE8re de contr\xF4le\xBB.
+\end{regle}
+
+Pour former un caract\xE8re de contr\xF4le, on peut donc utiliser des caract\xE8res de catcode 12\idx*{catcode!12 (autre)} comme par exemple \xAB\verb|\.|\xBB, \xAB\verb|\*|\xBB, \xAB\verb|\5|\xBB ou \xAB\verb|\@|\xBB. Il devient surtout possible d'employer des caract\xE8res dont le catcode est plus sensible comme \xAB\verb|\\|\xBB, \xAB\verb|\{|\xBB, \xAB\verb|\}|\xBB, \xAB\verb|\^|\xBB, \xAB\verb|\_|\xBB, \xAB\verb|\&|\xBB, \xAB\verb|\~|\xBB, \xAB\verb|\%|\xBB. Ces derniers, \xE0 l'exception de \verb|\\|\footnote{La macro \texttt{\string\\} est d\xE9finie par plain-\TeX{} car elle est utilis\xE9e comme macro auxiliaire pour d\xE9finir une autre macro et la d\xE9finition qui lui est donn\xE9e \xE0 cette occasion est laiss\xE9e en l'\xE9tat. Toujours est-il qu'elle n'affiche pas \xAB\texttt{\textbackslash}\xBB, qui s'obtient avec \xAB\texttt{\textbackslash char\number`\\}\xBB ou mieux avec \xAB\texttt{\textbackslash char`\textbackslash\textbackslash}\xBB.
+
+Du c\xF4t\xE9 de \LaTeX{}, la macro \texttt{\string\\} est d\xE9finie pour commander d'aller \xE0 la ligne pendant le paragraphe en cours et est red\xE9finie dans plusieurs environnements (centering, raggedright, raggedleft, eqnarray, tabbing, array, tabular).}, sont d\xE9finis par plain-\TeX{} pour afficher le caract\xE8re qui forme leur nom, caract\xE8re qu'il serait plus difficile d'afficher sinon. Pour cela, la primitive \idx\chardef est employ\xE9e avec cette syntaxe :
+
+\centrecode-\chardef\<macro>=<code de caract\xE8re>-
+
+\noindent Si l'on s'int\xE9resse au code des macros du format plain-\TeX{} qui est contenu dans le fichier \xAB\verb|plain.tex|\xBB\idx*{fichier!plain.tex}, on d\xE9couvre par exemple \xE0 la ligne \no 651 que le caract\xE8re de contr\xF4le \idx\& est d\xE9fini par
+
+\centrecode-\chardef\&=`\&-
+
+\noindent ce qui a pour effet de rendre \xE9quivalent (\xE0 la mani\xE8re de \idx\let) le caract\xE8re de contr\xF4le \verb|\&| \xE0 \xAB\idx\char\verb|`\&|\xBB.
+
+\begin{regle}
+Contrairement aux s\xE9quences de contr\xF4le dont le nom est form\xE9 de lettres, les \idx{espace}s qui suivent les \xAB caract\xE8res de contr\xF4le \xBB ne sont pas ignor\xE9s. La seule exception est la primitive \idx\ , qui ajoute un espace \xE0 la liste courante. En effet, si cette derni\xE8re est suivie d'un espace, alors deux \idx[!cons\xE9cutifs]{espace}s se suivent dans le code et une autre r\xE8gle stipule que le second est ignor\xE9.
+\end{regle}
+
+\begin{exercice}
+En ayant fait les d\xE9finitions \xAB\verb*-\def\9{\ \:}-\xBB et \xAB\verb*-\def\:{ \  X}-\xBB, quel affichage obtiendra-t-on avec \xAB\verb*-a\9 fin-\xBB ?
+\solution
+On obtient la lettre \xABa\xBB suivie du texte de remplacement de \verb-\9-. Celui-ci commence par \verb*-\ - (espace qui sera affich\xE9) suivi de \verb-\:-. Le texte de remplacement de \verb|\:| commence par : \verb*- - (espace qui sera affich\xE9) puis \verb*-\  - (le deuxi\xE8me espace est ignor\xE9) suivi d'un \xAB\verb|X|\xBB. Et enfin, l'espace apr\xE8s \verb*-\9 - sera affich\xE9 avant le mot \xABfin\xBB. On obtient donc \xABa\verb*-   -X\verb*- -fin\xBB.
+\end{exercice}
+
+\begin{exercice}
+\Qu elle diff\xE9rence y t-il entre \xAB\verb-\+-\xBB et \xAB\idx\csname\verb|+|\idx\endcsname\xBB
+ ?
+\solution
+Il n'y a pas de diff\xE9rence \xE0 l'affichage sauf si le caract\xE8re qui suit dans le code est un espace. Il sera comptabilis\xE9 avec \verb-\+- et ignor\xE9 avec \idx\csname\verb|+|\idx\endcsname car l'espace qui suit la \idx{s\xE9quence de contr\xF4le} \idx\endcsname est ignor\xE9.
+
+De plus, si le caract\xE8re de contr\xF4le \verb-\+- n'a pas \xE9t\xE9 d\xE9fini, \xE9crire \verb-\+- provoque une erreur \xE0 la compilation de type \xAB\texttt{Undefined control sequence}\xBB. Au contraire, avec \idx\csname\verb|+|\idx\endcsname, il n'y aurait pas d'erreur car lorsque \idx\csname construit une \idx{s\xE9quence de contr\xF4le} non d\xE9finie, elle la rend \xE9gale \xE0 \idx\relax, et ici, tout se passerait comme si on avait \xE9crit \idx\let\verb|\+=|\idx\relax.
+\end{exercice}
+\begin{exercice}
+\Qu elle diff\xE9rence y a-t-il entre \xAB\idx\def\verb-\foo{A}-\xBB et \xAB\idx\let\verb-\foo=A-\xBB ?
+\solution
+\xC0 l'affichage, dans les deux cas, \verb-\foo- produit un \xABA\xBB. Par contre, en interne, les choses sont diff\xE9rentes\ldots
+
+Lorsque \verb-\foo- est d\xE9finie avec \idx\def, \TeX{} la \emph{remplace} par un \xABA\xBB.
+
+Lorsque \verb-\foo- est d\xE9finie avec \idx\let, aucun remplacement n'est fait puisque \verb-\foo- \emph{est} un \xABA\xBB et n'a aucun texte de remplacement.
+\end{exercice}
+
+Le fait que les commandes caract\xE8res prennent en compte les espaces qui les suivent permet de d\xE9finir un espace implicite \xA7\sptoken de cette fa\xE7on\footnote{C'est ainsi que \texttt{\string\@sptoken} est d\xE9fini dans le code du noyau \LaTeX.} :\label{sptoken}
+
+\centrecodespc/\def\:{\let\sptoken= }\xA4\xA7*\sptoken\xA4
+\: /
+
+\noindent Toute l'astuce r\xE9side dans le fait que l'espace qui suit \verb|\:| \xE0 la 2\ieme{} ligne est pris en compte. La man\-\oe uvre m\xE9rite une petite explication. La premi\xE8re ligne d\xE9finit un texte de remplacement pour la macro \verb|\:|. \xC0 la deuxi\xE8me ligne, \TeX{} va remplacer \verb|\:| par son texte de remplacement ce qui va donner :
+
+\begin{centrage}
+\small\boxtoken{\let\string\sptoken= }\verb*| |%
+\end{centrage}
+
+Pour plus de clart\xE9, le texte de remplacement de \verb|\:| est encadr\xE9. Dans ce texte de remplacement, l'espace qui suit le signe \verb|=| est l'espace facultatif qui est permis avec la primitive \idx\let. Cet espace, faisant partie de la syntaxe de \idx\let, est ignor\xE9 et donc, \idx\let rend \xA7\sptoken \xE9gal au token suivant qui est \xAB\verb*| |\xBB, l'espace qui suit le caract\xE8re de contr\xF4le \verb|\:|.
+
+Dans le code ci-dessus, le second espace n'est pas ignor\xE9 car les deux espaces ne sont pas cons\xE9cutifs dans le code source. Ils sont cons\xE9cutifs apr\xE8s que \TeX{} ait remplac\xE9 \verb|\:| par son texte de remplacement. La r\xE8gle de la page~\pageref{regle.espace} ne s'applique donc pas.
+
+\begin{exercice}
+Comment serait d\xE9fini \xA7\sptoken si l'on \xE9crivait na\xEFvement \idx\let\verb*-\sptoken=  - ?
+\solution
+Comme on l'a vu, le premier espace, facultatif, fait partie de la syntaxe de \idx\let et ne peut donc pas servir \xE0 d\xE9finir \xA7\sptoken. Le second est ignor\xE9 puisque la r\xE8gle veut que deux espaces cons\xE9cutifs dans le code n'en forment qu'un.
+
+Dans ce cas, \xA7\sptoken sera un alias pour le token qui \emph{suivra dans le code} et que l'on n'a pas pr\xE9cis\xE9 dans l'\xE9nonc\xE9 de l'exercice. Il faut noter que si ce qui suit est un saut de ligne, \xA7\sptoken sera un alias de la commande \idx\par car deux sauts de lignes cons\xE9cutifs sont \xE9quivalents \xE0 la commande \idx\par :
+
+\showcode/\let\sptoken=  %2 espaces avant le "%"\xA4\xA7*\sptoken\xA4
+
+La commande \sptoken compose le paragraphe/
+\end{exercice}\idx*[|)]{caract\xE8re de contr\xF4le}
+
+\section{Caract\xE8res actifs}\idx*[|(]{caract\xE8re actif}
+Un caract\xE8re est dit \emph{actif} lorsqu'il rev\xEAt les m\xEAmes propri\xE9t\xE9s qu'une commande : on peut le d\xE9finir avec \idx\def et, lorsqu'il est rencontr\xE9 par \TeX{}, son texte de remplacement lui est substitu\xE9. En contrepartie, il ne fait plus partie de la cat\xE9gorie de lettres et n'est donc pas autoris\xE9 dans les noms des s\xE9quences de contr\xF4le.
+
+\begin{regle}
+Un caract\xE8re est \emph{actif} lorsque son code de cat\xE9gorie vaut 13\idx*[!13 (actif)]\catcode. Dans ce cas, on peut lui donner un texte de remplacement comme on le fait pour une macro.
+\end{regle}
+
+Par d\xE9faut, aussi bien avec plain-\TeX{} qu'avec \LaTeX, seul le caract\xE8re \xAB\cidx\~\xBB est actif fait les choses suivantes :
+\begin{enumerate}
+	\item interdire une coupure en sp\xE9cifiant une haute \idx{p\xE9nalit\xE9} (avec la primitive \idx\penalty suivie d'un entier \xE9lev\xE9, par exemple \numprint{1000});
+	\item appeler la primitive \idx\ qui affiche une espace.
+\end{enumerate}
+Ainsi, plain-\TeX{} dit :
+
+\centrecode-\def~{\penalty1000 \ }-
+
+\noindent La forte \idx{p\xE9nalit\xE9} de \texttt{1000} interdit toute coupure et le tout forme donc une \xAB \idx[!ins\xE9cable]{espace} ins\xE9cable \xBB, o\xF9 l'adjectif \emph{ins\xE9cable} exprime que cette espace ne pourra donner lieu \xE0 une coupure de ligne.
+\grandsaut
+
+\xC0 notre tour, supposons que l'on souhaite rendre le caract\xE8re \xAB\verb|W|\xBB actif. Nous le ferons \xE0 l'int\xE9rieur d'un groupe, car il est prudent de limiter la port\xE9e des modifications des codes de cat\xE9gorie.
+
+Nous savons que \idx\catcode\verb-`\<car>=<nombre>- modifie le catcode d'un caract\xE8re, o\xF9 \verb-<nombre>- est un nombre de 0 \xE0 15\footnote{Le caract\xE8re \xAB\texttt`\xBB est l'apostrophe \emph{inverse} et s'obtient parfois en tapant la combinaison de touches \bioLegacyKeyGlyph{A_l_t_G_r}+\bioLegacyKeyGlyph{seven}. Pour exprimer le nombre \xE9gal au code de cat\xE9gorie d'un caract\xE8re, on peut \xE9crire \verb|\`<car>| ou \verb|`<car>|. La seconde \xE9criture est cependant moins recommandable puisque l'on s'expose \xE0 des erreurs lorsque \verb|<car>| a un catcode sp\xE9cial (0 ou \number\catcode`\%).}. Ici, on va donc \xE9crire \verb-\catcode`\W=13-. Et ensuite, il suffit de d\xE9finir le texte de remplacement du caract\xE8re actif \verb|W|, par exemple \xABwagons\xBB :
+
+\showcode/{% d\xE9but du groupe
+\catcode`\W=13 \def W{wagons}\xA4\idx*\catcode\xA4
+Les W constituent le train.
+}% fin du groupe/
+
+Voici la r\xE8gle corroborant ce que l'on constate dans l'exemple ci-dessus :
+
+\begin{regle}
+Un \idx{espace} apr\xE8s un caract\xE8re actif est pris en compte.
+\end{regle}
+
+Il est plus difficile est de cr\xE9er une commande qui rende le caract\xE8re \verb|W| actif. Appelons \verb-\actiw- cette commande et donnons-nous le cahier des charges suivant : elle devra rendre le caract\xE8re \verb|W| actif et lui donner le texte de remplacement \xABwagons\xBB. Nous placerons un \idx\begingroup avant d'appeler cette macro et un \idx\endgroup \xE0 la fin du texte o\xF9 l'on souhaite que le caract\xE8re \verb|W| soit actif.
+
+Pour d\xE9finir cette commande \verb-\actiw-, on ne peut pas \xE9crire directement ceci :
+
+\centrecode-\def\actiw{\catcode`\W=13 \def W{wagons}}-
+
+\noindent En effet, lorsque \TeX{} remplace \verb|\actiw| par son texte de remplacement, \emph{tous} les tokens dans ce texte de remplacement ont leurs catcodes fig\xE9s depuis que la d\xE9finition a \xE9t\xE9 faite. Et donc, le \xAB\verb|W|\xBB qui suit le \verb|\def| a un catcode de 11.
+
+Par cons\xE9quent, lorsque ce texte de remplacement sera ex\xE9cut\xE9, \TeX{} va trouver \verb-\def W{wagons}- o\xF9 \verb|W| est une lettre (de catcode 11\idx*{catcode!11 (lettre)}), et il va se plaindre de ne pas trouver une \idx{s\xE9quence de contr\xF4le} apr\xE8s le \idx\def en affichant le message d'erreur \xAB\texttt{Missing control sequence}\xBB.
+
+Il faut comprendre que l'ordre \xAB\verb|\catcode`\W=13|\xBB qui est dans texte de remplacement ne peut pas agir sur les \xAB\verb|W|\xBB de ce texte de remplacement puisque leurs catcodes sont fig\xE9s, mais agira sur le code qui reste \xE0 lire \emph{apr\xE8s} \verb|\actiw|.
+
+Pour sortir de ce mauvais pas, il faut rendre \verb|W| actif \emph{avant} que \TeX{} ne lise le texte de remplacement de \verb-\wagon-. Pour limiter la port\xE9e de cette op\xE9ration, on va donc le faire dans un groupe et utiliser \idx\gdef, pour que la d\xE9finition soit globale et survive \xE0 la fermeture du groupe. Voici la fa\xE7on correcte de d\xE9finir \verb-\actiw- :
+
+\showcode/\begingroup \catcode`\W=13 \xA4\idx*\begingroup\idx*\endgroup\xA4
+\gdef\actiw{%\xA4\idx*\gdef\xA4
+	\catcode`\W=13 \xA4\idx*\catcode\xA4
+	\def W{wagons}}
+\endgroup
+a) Les trains ne sont pas constitu\xE9s de W !\par
+b) \begingroup\actiw Ici, les W forment les trains.\endgroup\par
+c) Ici, les W sont redevenus des lettres./
+
+\begin{exercice}
+D\xE9finir deux s\xE9quences de contr\xF4le \verb-\>- et \verb-\<- telles qu'entre elles, les mots soient espac\xE9s de \numprint[mm]5. Le comportement normal doit \xEAtre r\xE9tabli ensuite.
+
+On utilisera la primitive \idx\hskip suivie d'une dimension pour ordonner \xE0 \TeX{} d'ins\xE9rer une espace horizontale de la valeur de la dimension.
+\solution
+Comme on l'a vu, on ne peut pas \xE9crire directement ce code comme ci-dessous pour d\xE9finir la macro \verb-\>- :
+
+\centrecode-\def\>{\begingroup\catcode`\ =13 \def {\hspace{5mm}}}-
+
+\noindent puisqu'au moment o\xF9 cette ligne est lue par \TeX{}, l'espace a son code de cat\xE9gorie naturel de 10. Celui-ci ne pourra plus \xEAtre chang\xE9 par la suite.
+
+Voici la bonne fa\xE7on de proc\xE9der : il suffit de rendre la commande \verb-\<- \xE9gale \xE0 \idx\endgroup ce qui cl\xF4turera le processus initi\xE9 par \verb-\>- qui avait ouvert le groupe semi-simple :
+
+\showcode/\begingroup\xA4\idx*\begingroup\xA4
+	\catcode`\ =13 % rend l'espace actif\xA4\idx*\catcode\xA4
+	\gdef\>{\begingroup\xA4\idx*\gdef\xA4
+		\catcode`\ =13
+		\def {\hskip5mm\relax}}\xA4\idx*\hskip\idx*\relax\xA4
+\endgroup
+\let\<=\endgroup\xA4\idx*\let\xA4
+a) Du texte normal\par
+b) \>Des mots tr\xE8s espac\xE9s\<\par
+c) Du texte normal/
+\end{exercice}
+
+La pr\xE9sence d'un \idx\relax apr\xE8s la dimension de \verb|5mm| stoppe la lecture de la dimension. En effet, comme nous le verrons plus loin, une dimension peut avoir des composantes \xE9tirables qui commencent par le mot-cl\xE9 \xAB\verb|plus|\xBB. Sans le \idx\relax, si jamais un espace actif \xE9tait suivi du mot \xAB\verb|plus|\xBB, alors \TeX{} penserait que ce mot fait partie int\xE9grante de la dimension et irait chercher encore plus loin la composante \xE9tirable. Le \verb|\relax| agit donc ici comme une s\xE9curit\xE9.
+\grandsaut
+
+Une application utile des caract\xE8res actifs est de rendre les signes de ponctuation haute actifs. C'est ce que fait l'extension pour \LaTeX{} \xAB\verb-babel-\xBB charg\xE9e avec l'option \xAB\verb-frenchb-\xBB de Daniel \textsc{Flipo}\idx*{package!babel (frenchb)}. Les signes de ponctuation \emph{haute} \xAB\string!\xBB, \xAB\string?\xBB, \xAB\string:\xBB et \xAB\string;\xBB sont rendus actifs de fa\xE7on \xE0 ins\xE9rer une espace fine ins\xE9cable avant eux. Nous allons imiter ce comportement et rendre la virgule active. L'id\xE9e est de la programmer pour qu'elle supprime un \xE9ventuel espace avant elle, affiche le caract\xE8re \xAB\verb|,|\xBB, ins\xE8re une espace justifiante (c'est-\xE0-dire \xE9tirable) et enfin, ne tienne pas compte des espaces qui pourraient suivre. Pour effectuer ces actions, certaines primitives sont n\xE9cessaires :
+\begin{itemize}
+	\item si ce qui pr\xE9c\xE8de est un espace \xE9tirable, la primitive \idx\unskip le supprime ;
+	\item \idx\string transforme le token qui suit en un ou plusieurs tokens dont les codes de cat\xE9gorie sont 12. Cette primitive est utile pour rendre n'importe quel \idx{token} inoffensif et donc imm\xE9diatement affichable. Par exemple, \xAB\verb-\string#-\xBB produit \xAB\string#\xBB de m\xEAme que \xAB\verb-\string\def-\xBB produit \xAB\string\def\xBB. Lorsque la virgule sera active, \xAB\verb-\string,-\xBB affichera une virgule non active;
+	\item \idx\ignorespaces demande \xE0 \TeX{} d'ignorer tous les espaces qui vont suivre et d'avancer sa t\xEAte de lecture jusqu'au prochain caract\xE8re qui n'est pas un espace.
+\end{itemize}
+
+\showcode/\begingroup\xA4\idx*\begingroup\xA4
+	\catcode`\,=13 \def,{\unskip\string,\space\ignorespaces}\xA4\idx*\unskip\idx*\string\idx*\space\idx*\ignorespaces\idx*\catcode\xA4
+	La rue assourdissante autour de moi hurlait.
+
+	Longue , mince,en grand deuil  ,  douleur majestueuse ,
+
+	Une femme passa   ,d'une main fastueuse
+
+	Soulevant,balan\xE7ant le feston et l'ourlet ;
+
+\endgroup\medbreak\hfill Charles {\sc Baudelaire}\xA4\idx*\endgroup\idx*\medbreak\idx*\hfill\idx*\sc\xA4/
+
+\begin{exercice}
+Par d\xE9faut, le caract\xE8re ins\xE9r\xE9 par \TeX{} \xE0 chaque \idx{fin de ligne} est le retour charriot, qui s'\xE9crit \xAB\verb-^^M-\verbidx*[ (retour charriot)]{^^M}\xBB et qui a comme code de cat\xE9gorie \number\catcode`\^^M. La r\xE8gle de \TeX{} vue page~\pageref{regle.catcode5} veut que \emph{deux} retours charriots cons\xE9cutifs (ou plus g\xE9n\xE9ralement deux tokens cons\xE9cutifs de catcode \number\catcode`\^^M) soient \xE9quivalents \xE0 la commande \idx\par\idx*{catcode!5 (retour charriot)}.
+
+Reprendre l'exemple pr\xE9c\xE9dent en faisant en sorte qu'un seul retour charriot suffise \xE0 aller \xE0 la ligne suivante.
+\solution
+Il suffit de rendre le caract\xE8re \verb-^^M- actif et le rendre \xE9gal \xE0 \idx\par avec un \idx\let :
+
+\showcode/\begingroup\xA4\idx*[|etc]\begingroup\forbidindex\begingroup\xA4
+	\catcode`\,=13 \def,{\unskip\string, \ignorespaces}\xA4\idx*\unskip\idx*\string\idx*\ignorespaces\idx*\catcode\xA4
+	\catcode`\^^M=13 \let ^^M\par\xA4\idx*\let\xA4 % rend le retour charriot \xE9gal \xE0 \par
+	La rue assourdissante autour de moi hurlait.
+	Longue , mince,en grand deuil  , douleur majestueuse ,
+	Une femme passa   ,   d'une main fastueuse
+	Soulevant,balan\xE7ant le feston et l'ourlet ;
+\endgroup\medbreak\hfill Charles {\sc Baudelaire}\xA4\idx*[|etc]\endgroup\forbidindex\endgroup\idx*\medbreak\idx*\hfill\idx*\sc\xA4/
+\end{exercice}
+
+\begin{exercice}
+Dans un texte \xE0 l'int\xE9rieur d'un groupe, inventer un proc\xE9d\xE9 qui effectue un remplacement par permutation circulaire des voyelles, c'est-\xE0-dire qui remplace a par e, e par i, i par o, o par u, u par y et y par a.
+\solution
+\label{permutation.voyelles}La difficult\xE9 vient du fait qu'une fois qu'un caract\xE8re est rendu actif, il devient semblable \xE0 une \idx{s\xE9quence de contr\xF4le} et on ne peut plus s'en servir pour former le nom d'une \idx{s\xE9quence de contr\xF4le}. C'est donc une m\xE9thode peu recommandable, il en existe d'ailleurs de meilleures. Il n'emp\xEAche qu'en l'\xE9tat actuel de nos connaissances, nous ne pouvons proc\xE9der qu'en touchant aux codes de cat\xE9gorie.
+
+Avant de toucher aux catcodes des voyelles, on va donc d\xE9finir des s\xE9quences de contr\xF4le \verb-\AA-, \verb-\EE-, etc. qui, \xE0 l'aide de la commande \idx\let vont devenir des lettres implicites, \xABa\xBB pour \verb-\AA-, \xABe\xBB pour \verb-\EE-, etc.
+
+Ensuite, les commandes \idx\catcode et \verb|\let| contenant des voyelles, on ne pourra pas y faire appel apr\xE8s avoir modifi\xE9 les codes de cat\xE9gorie. On va donc d\xE9finir avec \verb-\let- des s\xE9quences de contr\xF4le \xE9quivalentes dont les voyelles seront en majuscule. On aura donc \verb-\lEt- pour \verb-\let- et \verb-\cAtcOdE- pour \verb-\catcode-.
+
+On peut ensuite rendre chaque voyelle active et la mettre \verb|let|-\xE9gale \xE0 \verb-\AA-, \verb-\EE-, etc. selon la lettre que l'on veut obtenir.
+
+\showcode[\def\`##1{{\accent0 ##1}}\def\'##1{{\accent1 ##1}}]/{% ouvre un groupe
+	\let\AA=a \let\EE=e \let\II=i \let\OO=o \let\UU=u \let\YY=y\xA4\idx*\let\xA4
+	% sauvegarder avant de modifier le catcode de a et e :
+	\let\lEt=\let \let\cAtcOdE=\catcode\xA4\idx*\catcode\xA4
+	\cAtcOdE`\a=13 \lEt a=\EE \cAtcOdE`\e=13 \lEt e=\II
+	\cAtcOdE`\i=13 \lEt i=\OO \cAtcOdE`\o=13 \lEt o=\UU
+	\cAtcOdE`\u=13 \lEt u=\YY \cAtcOdE`\y=13 \lEt y=\AA
+	Ce texte devenu \`a peine reconnaissable montre que le r\'esultat
+	contient des sonorit\'es catalanes, corses ou grecques assez
+	inattendues.
+}% ferme le groupe/
+
+Les contorsions n\xE9cessaires pour arriver \xE0 nos fins montrent que l'on ne touche pas aux codes de cat\xE9gorie sans se cr\xE9er de r\xE9elles difficult\xE9s et sans prendre de gros risques si l'on contr\xF4le mal la port\xE9e des modifications. Changer un code de cat\xE9gorie de caract\xE8re doit donc rester exceptionnel et rester r\xE9serv\xE9 \xE0 des buts tr\xE8s sp\xE9cifiques. En effet, des m\xE9thodes plus sures existent, m\xEAme si elles ont aussi d'autres inconv\xE9nients.
+
+Une optimisation du code serait d'utiliser le caract\xE8re d\xE9j\xE0 actif \xAB\cidx\~\xBB comme alias de \idx\catcode. Bien s\xFBr, on y perd en lisibilit\xE9\ldots{} On peut aussi profiter de la permutation circulaire pour d\xE9finir chaque voyelle rendue active comme alias de la prochaine voyelle, non encore rendue active. On \xE9conomise ainsi des s\xE9quences de contr\xF4le pour les lettres implicites. On n'en a besoin que d'une seule, \verb-\AA-, lettre implicite pour \xABa\xBB :
+
+\showcode[\def\`##1{{\accent0 ##1}}\def\'##1{{\accent1 ##1}}]/{%
+	\let\AA=a \let\lEt=\let \let~=\catcode\xA4\idx*\catcode\idx*\let\cidx*\~\xA4
+	~`a=13 \lEt a=e ~`e=13 \lEt e=i ~`i=13 \lEt i=o
+	~`o=13 \lEt o=u ~`u=13 \lEt u=y ~`y=13 \lEt y=\AA
+	Ce texte devenu \`a peine reconnaissable...
+}/
+\end{exercice}\idx*[|)]{caract\xE8re actif}
+
+\section{Signification d'une commande}
+Il est possible de demander \xE0 \TeX{} la \xAB signification \xBB d'une \idx[|etc]{s\xE9quence de contr\xF4le}\forbidindex{s\xE9quence de contr\xF4le}. Pour cela, la primitive \idx\show \xE9crit dans le \idx[!log]{fichier} log le \idx{texte de remplacement} de la macro ou simplement son nom si c'est une primitive. Cette primitive, lorsqu'elle est utilis\xE9e \xE0 bon escient dans le code permet un d\xE9bogage efficace par la lecture du \idx[!log]{fichier} \verb|log|. Pour diriger les informations d\xE9livr\xE9es par \idx\show dans le flux de lecture de \TeX{} pour par exemple les afficher dans le document final, il faut utiliser la primitive \idx\meaning.
+
+\showcode/a) \def\foo{Bonjour}\meaning\foo\par\xA4\idx*\meaning\xA4
+b) \let\bar=\foo\meaning\bar\par% \foo est "copi\xE9e" vers \bar
+c) \def\baz{\foo}\meaning\baz\par
+d) \catcode`\W=13 \def W{Wagons}% W est un caract\xE8re actif\xA4\idx*\catcode\xA4
+   \meaning W\par
+e) \meaning\def% \def est une primitive\xA4\idx*\meaning\xA4/
+
+Il est important d'insister entre la diff\xE9rence qui existe entre \verb|\let\bar\foo| (cas b) et \verb|\def\baz{\foo}| (cas c). Dans le premier cas, \verb|\bar| est rendue \xE9gale \xE0 \verb|\foo| et \xE0 partir de ce moment, \verb|\bar| a comme texte de remplacement \xABBonjour\xBB, ind\xE9pendamment de ce que devient \verb|\foo|. En revanche, lorsqu'on \xE9crit \verb|\def\baz{\foo}|, la macro \verb|\baz| a comme texte de remplacement \verb|\foo| et donc, \xE0 chaque fois qu'elle est ex\xE9cut\xE9e, elle d\xE9pend de ce qu'est \verb|\foo| \xE0 ce moment-l\xE0.
+
+\begin{exercice}
+Mettre en \xE9vidence \xE0 l'aide de la primitive \idx\meaning que 2 retours charriots\verbidx*[ (retour charriot)]{^^M} cons\xE9cutifs sont interpr\xE9t\xE9s par \TeX{} comme \xE9tant la primitive \verb-\par-.
+\solution
+Il suffit de d\xE9finir une commande dont le texte de remplacement est constitu\xE9 de 2 retours charriots cons\xE9cutifs et de faire afficher \xE0 \TeX{} la signification de cette commande, voire faire suivre \verb|\meaning| de deux retours \xE0 la ligne :
+
+\showcode/a) \def\foo{
+
+}Signification de \string\foo{} : \meaning\foo\xA4\idx*\string\idx*\meaning\xA4
+
+b) Signification de deux retours charriots cons\xE9cutifs : \meaning
+ /
+\end{exercice}
+
+\begin{regle}
+La primitive \idx\show \xE9crit dans le \idx[!log]{fichier} \verb|log| la \xAB signification \xBB du token\idx*[!signification]{token} qui la suit :
+	\begin{enumerate}
+		\item si ce token est une macro (ou un caract\xE8re actif), le texte \xAB\texttt{macro->}\xBB suivi du \idx{texte de remplacement} de cette macro est \xE9crit;
+		\item si ce token est une primitive, qui par d\xE9finition n'a pas de \idx{texte de remplacement}, le nom de la primitive est \xE9crit;
+		\item sinon, \TeX{} \xE9crit un texte bref (caract\xE9risant le catcode du token) suivi du token.
+	\end{enumerate}
+La primitive \idx\meaning \xE9crit les m\xEAmes choses que \idx\show sauf qu'elle les \xE9crits dans le flux de lecture de \TeX{}, dans la \idx{pile d'entr\xE9e}.
+\end{regle}
+
+Voici ce que provoque \verb|\meaning| pour les tokens de chaque cat\xE9gorie qu'il est possible de mettre apr\xE8s \verb|\meaning| :
+\begingroup
+\def~{\penalty\@M \ }
+\showcode/a) \meaning\relax\par% primitive\xA4\idx*\meaning\xA4
+b) \meaning {\par% catcode 1
+c) \meaning }\par% catcode 2
+d) \meaning $\par% catcode 3
+e) \meaning &\par% catcode 4
+g) \meaning #\par% catcode 6
+h) \meaning ^\par% catcode 7\xA4\idx*{catcode!7\space(exposant)}\xA4
+i) \meaning _\par% catcode 8
+j) \meaning a\par% catcode 11 (une lettre)\xA4\idx*{catcode!11\space(lettre)}\xA4
+k) \meaning +\par% catcode 12 (caract\xE8re "autre")\xA4\idx*{catcode!12\space(autre)}\xA4
+l) \meaning ~\par% catcode 13 (caract\xE8re actif)\xA4\idx*{catcode!13\space(actif)}\xA4/%
+\endgroup\iffalse$\fi
+
+\begin{exercice}
+On ne peut pas afficher la signification d'un espace (catcode 10\idx*{catcode!10 (espace)}) puisqu'\xE9crire \xAB\idx\meaning\verb*| |\xBB ferait que l'espace qui suit la primitive serait ignor\xE9 et \idx\meaning prendrait le token d'apr\xE8s. Comment s'y prendre pour afficher la signification d'un espace avec \idx\meaning ?
+\solution
+On peut employer la m\xEAme astuce qu'avec \xA7\sptoken de la page~\pageref{sptoken}. On s'y prend
+ ici avec \idx\let, en enfermant le tout dans un groupe semi-simple :
+
+\showcode/\begingroup% dans un groupe\xA4\idx*\begingroup\xA4
+	\let\*=\meaning% rendre \* \xE9gal \xE0 \meaning\xA4\idx*\meaning\xA4
+	\* %<- espace pris en compte
+\endgroup% fermer le groupe\xA4\idx*\endgroup\xA4/
+
+En revanche, on ne peut pas \xE9crire apr\xE8s \idx\meaning les caract\xE8res de catcode suivants :
+\begin{itemize}
+	\item 0 car le caract\xE8re d'\xE9chappement s'apparie toujours avec autre chose pour former une \idx{s\xE9quence de contr\xF4le}. Un token de catcode 0\idx*{catcode!0 (caract\xE8re d'\xE9chappement)} ne peut exister comme entit\xE9 seule;
+	\item 5 car ce caract\xE8re est vu comme un espace;
+	\item 9 car c'est le num\xE9ro de la cat\xE9gorie des caract\xE8res \xABignor\xE9s\xBB et le token serait aussi ignor\xE9, m\xEAme apr\xE8s \idx\meaning;
+	\item 14 car un caract\xE8re de commentaire est ignor\xE9 ainsi que tout ce qui va jusqu'\xE0 la fin de la ligne;
+	\item 15 car un caract\xE8re \xAB invalide \xBB n'est pas permis et provoque une erreur de compilation lorsqu'il est vu par \TeX{}.
+\end{itemize}
+\end{exercice}
+
+\section{Le caract\xE8re d'\xE9chappement}\idx*[|(]{caract\xE8re d'\xE9chappement}
+Par d\xE9faut, le caract\xE8re d'\xE9chappement est \xAB\cidx\\\xBB, c'est \xE0 ce caract\xE8re que \TeX{} reconnait le d\xE9but d'une \idx{s\xE9quence de contr\xF4le}. Comme presque tout dans \TeX{}, ce caract\xE8re est modifiable. En effet, tout caract\xE8re de catcode 0\idx*{catcode!0 (caract\xE8re d'\xE9chappement)} est, par d\xE9finition, un caract\xE8re d'\xE9chappement. Supposons qu'\xE0 l'int\xE9rieur d'un groupe semi-simple, on donne \xE0 \xAB\verb-*-\xBB le code de cat\xE9gorie 0 et \xE0 \xAB\verb-\-\xBB le code de cat\xE9gorie 12 qui est celui des caract\xE8res \xABautres\xBB. Ayant fait ces modifications, nous devrons mettre \xAB\verb-*-\xBB devant les s\xE9quences de contr\xF4le et pourrons alors afficher \xAB\verb-\-\xBB directement puisqu'il sera devenu un caract\xE8re inoffensif :
+
+\showcode/\begingroup\xA4\idx*\begingroup\xA4
+\catcode`\*0 \xA4\idx*\catcode\xA4
+\catcode`\\12 % \ n'est plus un caract\xE8re d'\xE9chappement
+*def*foo{bar}
+*LaTeX{} et la macro *string*foo : *foo.
+
+L'ancien caract\xE8re d'\xE9chappement  "\" et \TeX.
+*endgroup/
+
+\begin{exercice}
+Concernant l'exemple pr\xE9c\xE9dent :
+\begin{enumerate}
+	\item Aurait-on pu \xE9crire \xE0 la ligne 3 ceci : \xAB\verb-*catcode`*\12-\xBB\idx*\catcode ?
+	\item Si l'on avait utilis\xE9 \idx*\gdef\verb-*gdef- pour que la macro \verb-*foo- survive \xE0 la fermeture du groupe, aurait-on pu l'appeler par la suite avec \verb-\foo- ?
+\end{enumerate}
+\solution
+\begin{enumerate}
+	\item Apr\xE8s la ligne \no2, il y a 2 caract\xE8res d'\xE9chappement qui sont \xAB\verb-\-\xBB et \xAB\verb-*-\xBB. Tant qu'ils ont ce pouvoir, ils sont interchangeables. La r\xE9ponse est donc oui.
+	
+	En revanche, la ligne 2 fait perdre ce pouvoir au caract\xE8re \xAB\verb-\-\xBB ce qui fait qu'ensuite, seul \xAB\verb-*-\xBB peut \xEAtre utilis\xE9 comme caract\xE8re d'\xE9chappement jusqu'\xE0 ce que le groupe soit ferm\xE9 par \verb-*endgroup-\idx*\endgroup.
+	\item N'importe quel caract\xE8re ayant le catcode 0\idx*{catcode!0 (caract\xE8re d'\xE9chappement)} peut \xEAtre utilis\xE9 pour amorcer le nom d'une macro. En temps normal, seul \xAB\verb-\-\xBB est disponible donc la r\xE9ponse est oui.
+\end{enumerate}
+\end{exercice}
+
+On peut observer que \idx\string, qui convertit le nom d'une \idx{s\xE9quence de contr\xF4le} en caract\xE8res de catcode 12\idx*{catcode!12 (autre)}, ne tient pas compte de la modification du caract\xE8re d'\xE9chappement puisque l'on obtient \verb-\foo- et non pas \verb-*foo-. Cela dit, ce comportement est un peu normal car s'il y avait plusieurs caract\xE8res d'\xE9chappement, \TeX{} serait bien ennuy\xE9 pour en choisir un. Pour sch\xE9matiser, on peut consid\xE9rer que le choix d'un caract\xE8re d'\xE9chappement par son catcode concerne un m\xE9canisme d'\emph{entr\xE9e} pour \TeX{} puisqu'il s'agit d'une r\xE8gle concernant la lecture du code tap\xE9 par l'utilisateur. La primitive \idx\string appliqu\xE9e aux macros, au contraire, concerne un m\xE9canisme de sortie puisqu'elle provoque la conversion d'une donn\xE9e interne de \TeX{} (le nom de la macro) en caract\xE8res imm\xE9diatement affichables. Ces deux m\xE9canismes se repr\xE9sentent le caract\xE8re d'\xE9chappement par des moyens ind\xE9pendants. Pour \idx\string, il faut le d\xE9finir via la primitive \idx\escapechar qui attend apr\xE8s elle le code de caract\xE8re du caract\xE8re d'\xE9chappement que l'on souhaite. Dans l'exemple pr\xE9c\xE9dent pour que le caract\xE8re d'\xE9chappement affich\xE9 par \idx\string soit \xAB\verb- at -\xBB, il suffit de rajouter juste apr\xE8s le \idx\begingroup :
+
+\begin{centrage}
+	 \small\verb|\espcapechar=64 |\qquad ou bien\qquad \verb|\escapechar=`\@|
+\end{centrage}
+
+Notons que tout comme \idx\string, les primitives \idx\meaning et \idx\show tiennent compte de la modification du \idx\escapechar. Enfin, si l'on assigne \xE0 \idx\escapechar un code inf\xE9rieur \xE0 0 ou sup\xE9rieur \xE0 255, alors aucun caract\xE8re d'\xE9chappement ne pr\xE9c\xE8dera le nom de la macro.
+
+\showcode/\def\foo{\bar}
+\begingroup\xA4\idx*\begingroup\xA4
+a) \escapechar=-1  \meaning\foo\qquad% pas de caract\xE8re d'\xE9chappement\xA4\idx*\escapechar\idx*\meaning\idx*\qquad\xA4
+b) \escapechar=`\@ \meaning\foo\qquad% "@" est le caract\xE8re d'\xE9chappement
+\endgroup\xA4\idx*\endgroup\xA4
+c) \meaning\foo% caract\xE8re d'\xE9chappement par d\xE9faut/
+
+\begin{exercice}\label{construction.nom.etrange}
+D\xE9finir une commande dont le nom est \verb-\-\boxtoken{1\string\2\string\a} et dont le texte de remplacement est \xABfoo\xBB et v\xE9rifier en appelant cette commande que la d\xE9finition est bien correcte.
+\solution
+Il va falloir agir dans un groupe, modifier les catcodes de 1, 2 et \cidx\\ pour les mettre \xE0 11, cat\xE9gorie des lettres, seules autoris\xE9es dans les noms de macros. Comme \xAB\cidx\\\xBB est le caract\xE8re d'\xE9chappement, il va aussi falloir en d\xE9finir un autre, choisissons \xAB\verb-|-\xBB. Comme toutes ces man\-\oe uvres ont lieu dans un groupe, nous utiliserons \verb-|gdef-\idx*\gdef pour que la d\xE9finition de la macro survive \xE0 la fermeture du groupe.
+
+Le probl\xE8me ici est que l'on doit donner \emph{en dernier} \xE0 \xAB\verb|1|\xBB le catcode 11. En effet, si on le faisait avant, \xAB\verb|1|\xBB deviendrait pour \TeX{} une \emph{lettre} et lorsqu'il rencontrerait \verb-|catcode`|2=11-, le \xAB\verb|11|\xBB serait, \xE0 ses yeux, deux lettres qui ne peuvent former un nombre, car les tokens qui forment les nombres doivent avoir un catcode de 12\idx*{nombre!catcode des chiffres} ! Nous aurions droit \xE0 une erreur de compilation du type \xAB\texttt{Missing number}\xBB.
+
+Enfin, pour appeler la macro \xE0 l'ext\xE9rieur du groupe, on doit utiliser la paire \idx\csname...\linebreak[1]\idx\endcsname dans laquelle on prendra soin de transformer le caract\xE8re d'\xE9chappement \verb-\- en un caract\xE8re inoffensif de catcode 12\idx*{catcode!12 (autre)} avec la primitive \idx\string.
+
+\showcode/\begingroup
+	\catcode`\|=0 |catcode`|\=11 |catcode`|2=11 |catcode`|1=11 \xA4\idx*\catcode\forbidindex\catcode\xA4
+	|gdef|1\2\a{foo}\xA4\idx*\gdef\xA4
+|endgroup\xA4\idx*\endgroup\xA4
+Voici la macro : \csname 1\string\2\string\a\endcsname\xA4\idx*\string\idx*\csname\idx*\endcsname\xA4/
+
+Dans ce cas, ces manipulations de catcode, assez dangereuses et plut\xF4t chatouilleuses, sont fort heureusement inutiles avec la primitive \idx\expandafter que nous verrons plus loin. Il s'agit d'un exemple purement p\xE9dagogique\ldots
+\end{exercice}\idx*[|)]{caract\xE8re d'\xE9chappement}
+
+\section{Une autre fa\xE7on de stocker des tokens}
+Arriv\xE9s \xE0 ce point, nous savons qu'une macro peut servir \xE0 stocker des tokens. Ces tokens sont plac\xE9s dans le texte de remplacement de la macro lors de sa d\xE9finition avec \verb|\def|. Bien qu'on les utilise aussi dans ce but, les possibilit\xE9s d'une macro ne se limitent pas \xE0 ce simple stockage et c'est ce que nous allons d\xE9couvrir dans les chapitres suivants.
+
+Si l'on recherche uniquement le c\xF4t\xE9 \xAB stockage de tokens \xBB, \TeX{} propose un autre type de structure : les registres de tokens\idx*[|(]{registre!token}\idx*[|(]{token!registre}. Ce sont de zones de m\xE9moire (au nombre de 256 pour \TeX{} et \numprint{32768} pour \idx\eTeX) auxquelles on acc\xE8de \xE0 l'aide de la primitive \idx\toks suivie du num\xE9ro de registre. Ainsi, \verb|\toks17| fait r\xE9f\xE9rence au registre de token \no17. Il est admis que le registre \no0 sert de registre brouillon et peut \xEAtre utilis\xE9 sans trop de risque n'importe o\xF9.
+
+\TeX{} met aussi \xE0 disposition la primitive \idx\toksdef et par exemple, \xE9crire
+
+\centrecode-\toksdef\foo=17-\idx*\toks
+
+\noindent rend \verb|\foo| \xE9quivalent \xE0 \verb|\toks17| de telle sorte que le registre \no17 peut \xEAtre d\xE9sign\xE9 par la \idx{s\xE9quence de contr\xF4le} \verb|\foo|. L'\xE9quivalence dont il est question ici ressemble \xE0 celle de \idx\let en ce sens que \verb|\foo| n'aura pas de texte de remplacement, mais \emph{sera} \verb|\toks17|.
+
+Il est d\xE9conseill\xE9 d'utiliser un num\xE9ro non nul arbitrairement et sans pr\xE9caution, car il se pourrait que ce registre soit d\xE9j\xE0 utilis\xE9 et on pourrait \xE9craser son contenu et provoquer des dysfonctionnements par la suite. Plain-\TeX{} propose la macro \idx\newtoks\verb-\<nom>- o\xF9 le \verb-\<nom>- sera une \idx{s\xE9quence de contr\xF4le} cr\xE9\xE9e par \TeX{} et qui, par l'interm\xE9diaire de la primitive \idx\toksdef, rendra \verb|\<nom>| \xE9quivalent \xE0 \idx\toks suivi du prochain num\xE9ro de registre inutilis\xE9. Gr\xE2ce \xE0 ce syst\xE8me, on peut donc demander en toute s\xE9curit\xE9 l'allocation d'un registre de tokens et y faire r\xE9f\xE9rence ensuite par un nom, ce qui est bien plus pratique \xE0 retenir qu'un num\xE9ro.
+
+Pour effectuer une assignation \xE0 un registre de tokens, il faut \xE9crire
+
+\centrecode-<registre de token>= {<ensemble de token>}-
+\noindent ou bien
+\centrecode-<registre de token>= <registre de token>-
+
+\noindent o\xF9 \verb|<registre de token>| est soit une \idx{s\xE9quence de contr\xF4le} d\xE9finie par \idx\toksdef ou \idx\newtoks, soit explicitement \idx\toks\verb|<num\xE9ro>|. Le signe \xAB=\xBB et l'espace qui le suit sont facultatifs et seront souvent omis.
+
+Pour extraire du registre ce qu'il contient, on doit faire appel \xE0 la primitive \idx\the suivie du \verb|<registre de token>|. Voici un exemple o\xF9 est sont cr\xE9\xE9s deux registres \verb-\foo- et \verb|\bar| :
+
+\showcode/\newtoks\foo% allocation d'un nouveau registre\xA4\idx*\newtoks\xA4
+\foo={Bonjour le monde}% assignation
+Contenu du registre {\tt\string\foo} : \the\foo.\xA4\idx*\the\idx*\tt\idx*\string\xA4
+
+\newtoks\bar% allocation d'un autre registre
+\bar=\foo% assigne \xE0 \bar les tokens du registre \foo
+Contenu du registre {\tt\string\bar} : \the\bar.\xA4\idx*\string\xA4/
+
+Comme pour les s\xE9quences de contr\xF4le, si l'assignation d'un registre \xE0 tokens se fait \xE0 l'int\xE9rieur d'un groupe, elle est annul\xE9e lors de sa fermeture \xE0 moins de faire pr\xE9c\xE9der l'assignation de \idx\global\idx*[|)]{registre!token}\idx*[|)]{token!registre}\idx*{assignation!registre de tokens}.
+
+\chapter{Arguments d'une commande}
+Les commandes vues jusqu'\xE0 pr\xE9sent \xE9taient immuables en ce sens que leur texte de remplacement \xE9tait fig\xE9 une bonne fois pour toutes. Avec cette limite, elles ne seraient ni tr\xE8s puissantes ni tr\xE8s int\xE9ressantes. Heureusement, les commandes peuvent admettre des \xAB arguments \xBB, variables eux, qui seront lus chaque fois que la commande sera appel\xE9e et qui seront ins\xE9r\xE9s \xE0 des endroits du texte de remplacement choisis par l'utilisateur.
+
+\section{\Qu 'est ce qu'un argument ?}
+
+\begin{regle}
+	Un \idx*{argument}argument d'une macro est :
+	
+	\begin{itemize}
+		\item soit un \idx{token} c'est-\xE0-dire un caract\xE8re (un \idx{octet}) ou une \idx{s\xE9quence de contr\xF4le};
+		\item soit le code qui se trouve entre deux accolades, \xE9tant entendu que ce code est un ensemble de tokens \xE9quilibr\xE9s en accolades ouvrantes et fermantes.
+	\end{itemize}
+\end{regle}
+
+\noindent Par exemple, si on les consid\xE8re comme des arguments de commandes :
+\begin{itemize}
+	\item \xAB\verb-a-\xBB repr\xE9sente un argument qui est \xAB\verb-a-\xBB;
+	\item \xAB\verb-abc-\xBB repr\xE9sente 3 arguments qui sont \xAB\verb-a-\xBB, \xAB\verb-b-\xBB et \xAB\verb-c-\xBB;
+	\item \xAB\verb*-ab c-\xBB constitue 3 arguments aussi, les m\xEAmes que ci-dessus. En effet, dans une liste d'arguments, un espace sous forme d'unit\xE9 lexicale est ignor\xE9. Pour qu'il soit pris en compte l'espace \emph{doit} \xEAtre mis entre accolades : \xAB\verb*- -\xBB n'est pas un argument alors que \xAB\verb*-{ }-\xBB en est un.
+	\item \xAB\verb-{abc}-\xBB est un argument unique qui est \xABabc\xBB;
+	\item \xAB\verb|\foo\bar|\xBB sont deux arguments, \xAB\verb|\foo|\xBB et \xAB\verb|\bar|\xBB;
+	\item \xAB\verb|{\foo\bar}|\xBB est un seul argument qui est \xAB\verb|\foo\bar|\xBB;
+	\item enfin, \xAB\verb*-{\def\AA{a}}{ }{c{d}e}{f}-\xBB est constitu\xE9 de quatre arguments :
+	\begin{enumerate}
+		\item \verb-\def\AA{a}-
+		\item \verb*- -
+		\item \verb-c{d}e-
+		\item \verb-f-
+	\end{enumerate}
+\end{itemize}
+
+\label{argument.espace}\begin{regle}
+Un espace \emph{non entour\xE9 d'accolades} est ignor\xE9 en tant qu'argument.\idx*[!argument]{espace}\idx*[!espace]{argument}
+\end{regle}
+
+Il faut retenir que les accolades ne servent qu'\xE0 d\xE9limiter l'argument et n'en font pas partie. Lorsque \TeX{} lit cet argument, il lit le texte se trouvant \xE0 int\xE9rieur des accolades et d\xE9pouille donc l'argument de ses \xE9ventuelles accolades ext\xE9rieures\idx*[!d\xE9limiteur d'argument]{accolade}.
+
+\begin{regle}
+Lorsque des accolades d\xE9limitent un argument d'une macro, elles ne jouent pas le r\xF4le de d\xE9limiteur de \emph{groupe}\idx*{argument!accolades}.
+\end{regle}\idx*[|(]{argument!accolades}
+
+\begin{exercice}
+Si on les consid\xE8re comme arguments d'une macro, \xAB\verb-a-\xBB et \xAB\verb-{a}-\xBB sont-ils diff\xE9rents ? Et si oui, en quoi ?
+\solution
+Non, s'ils sont les arguments d'une macro, \xAB\verb-a-\xBB et \xAB\verb-{a}-\xBB sont des arguments rigoureusement identiques et donc, si \verb|\foo| est une macro admettant un seul argument, il sera \xE9quivalent d'\xE9crire
+\begin{itemize}
+	\item \verb*|\foo a|
+	\item \verb|\foo{a}|
+\end{itemize}
+
+En revanche, si l'on souhaite donner la macro \verb|\bar| comme argument, il y aura une diff\xE9rence entre
+\begin{itemize}
+	\item \verb*|\foo\bar|
+	\item \verb|\foo{\bar}|
+\end{itemize}
+Dans le premier cas, si un espace est \xE0 suivre, il sera ignor\xE9 tandis qu'il sera bien pris en compte dans le second cas puisque venant \xE0 la suite d'une accolade et non pas d'une \idx{s\xE9quence de contr\xF4le}.
+
+Certains prennent l'habitude de ne jamais entourer d'accolades un argument constitu\xE9 d'une seule unit\xE9 lexicale. Il reste \xE0 savoir si cette habitude est bonne ou pas\ldots{} Je pencherais plut\xF4t pour dire qu'elle est bonne puisqu'elle facilite la lisibilit\xE9 en ne surchargeant pas le code d'accolades inutiles. Cependant, la pr\xE9sentation du code \xE9tant souvent une affaire de gouts personnels, d'autres trouveraient des arguments imparables pour pr\xE9f\xE9rer le contraire !
+\end{exercice}\idx*[|)]{argument!accolades}
+
+Pour d\xE9finir une commande qui admet des arguments\idx*{argument!token de param\xE8tre (\char`\#)|etc}, on utilise le token \xAB\cidx[ (token de param\xE8tre)]\#\xBB, de catcode \number\catcode`\#, dit \xABtoken de param\xE8tre\idx*[!de param\xE8tre]{token}\xBB que l'on fait suivre d'un entier qui repr\xE9sente le num\xE9ro de l'argument. Cet entier doit \xEAtre compris entre 1 et 9, ce qui signifie qu'une macro ne peut admettre que 9 arguments au maximum.
+
+Voici une macro \xAB\verb|\hello|\xBB, tr\xE8s simple, qui admet deux arguments et qui affiche \xAB Bonjour \verb|<argument 1>| et \verb|<argument 2>|.\xBB et qui compose le paragraphe courant \xE0 l'aide de \idx\par :
+
+\showcode/\def\hello#1#2{Bonjour #1 et #2.\par}% d\xE9finition
+\hello ab% #1=a et #2=b
+\hello a b% #1=a et #2=b
+\hello{foo}{bar}% #1=foo et #2=bar
+\hello foobar% #1=f et #2=o
+% (le reste "obar" est lu apr\xE8s que la macro est termin\xE9e)/
+
+Comme on le constate, \xE9crire
+
+\centrecode-\def\hello#1#2{Bonjour #1 et #2.\par}-
+
+\noindent signifie que la commande \verb-\foo- admet deux arguments qui seront \xE9crits \xAB\verb-#1-\xBB et \xAB\verb-#2-\xBB dans le \idx{texte de remplacement} de la macro. Lorsque \TeX{} va rencontrer \verb|\hello|, il lira \emph{aussi} les deux arguments qui suivent la commande. Il remplacera ces trois choses par le \idx{texte de remplacement} de la macro o\xF9 chaque \verb-#1- sera l'exact contenu du premier argument et chaque \verb-#2- celui du second.
+\grandsaut
+
+Lorsqu'on utilise \idx\def pour d\xE9finir une macro, ce qui est situ\xE9 entre le nom de la macro et l'accolade ouvrante qui d\xE9limite son texte de remplacement est appel\xE9 \xAB\idx{texte de param\xE8tre}\xBB. Dans l'exemple ci-dessus, ce texte de param\xE8tre est \verb-#1#2- et sp\xE9cifie que la commande \verb-\foo- admet 2 arguments. Dans le texte de param\xE8tre, les entiers qui suivent les caract\xE8res \verb-#- doivent commencer \xE0 1 pour le premier et aller en croissant de un en un. Il faut \xE9galement que les arguments rencontr\xE9s dans le \idx{texte de remplacement} existent \emph{aussi} dans le \idx{texte de param\xE8tre} sinon, \TeX{} \xE9met un message d'erreur \xAB\verb|Illegal parameter number in definition of \<macro>|\footnote{Nombre de param\xE8tres incorrect dans la d\xE9finition de \texttt{\char`\\\codeelement{macro}}.}\xBB. On ne peut donc pas \xE9crire
+
+\centrecode-\def\foo#1#2{Bonjour #1, #2 et #3}-
+
+\noindent car l'argument \verb|#3| n'est pas sp\xE9cifi\xE9 dans le \idx{texte de param\xE8tre}.
+
+\begin{regle}
+Une macro peut accepter de 0 \xE0 9 arguments\idx*{argument!nombre d'arguments}.
+
+Pour le sp\xE9cifier, on indique juste apr\xE8s \idx\def, dans le \xAB\idx{texte de param\xE8tre}\xBB, les arguments les uns \xE0 la suite des autres sous la forme \xAB\verb|#1|\xBB, \xAB\verb|#2|\xBB, et ainsi de suite jusqu'au nombre d'arguments que l'on veut donner \xE0 la macro.
+
+Le \idx{texte de param\xE8tre} est strict sur l'ordre des arguments, mais en revanche, il n'y a aucune contrainte sur l'ordre et l'existence des arguments dans le \idx{texte de remplacement} de la macro. On peut donc les y \xE9crire dans l'ordre que l'on veut, autant de fois que l'on souhaite, voire ne pas en \xE9crire certains.
+\end{regle}
+
+\begin{exercice}
+Comment s'y prendre pour qu'une commande traite plus de 9 arguments, par exemple 10 ?
+
+Programmer une macro \verb-\tenlist- qui lit 10 arguments (qui peuvent \xEAtre par exemple les 10 premi\xE8res lettres de l'alphabet) et les affiche de cette fa\xE7on :
+
+\begin{centrage}(a,b,c,d,e,f,g,h,i,j)\end{centrage}
+
+\solution
+On ne peut pas, \emph{stricto sensu}, programmer une macro qui admet 10 arguments, c'est une limitation intrins\xE8que \xE0 \TeX. Mais rien n'emp\xEAche d'en programmer une qui admet 9 arguments, traiter ces arguments comme on l'entend et une fois fini, passer la main \xE0 une autre commande qui admettra un argument, le lira et le traitera \xE0 son tour.
+
+On va donc \xE9crire :
+
+\centrecode-\def\tenlist#1#2#3#4#5#6#7#8#9{%
+	(#1,#2,#3,#4,#5,#6,#7,#8,#9\endlist
+}
+\def\endlist#1{,#1)}-
+
+Lorsque \TeX{} rencontrera la macro \verb-\tenlist-, il l'absorbera ainsi que les 9 arguments suivants (et uniquement eux) et il aura donc avanc\xE9 juste devant le 10\ieme{} argument. Il proc\xE8dera \xE0 la substitution de la macro et ses arguments par le texte de remplacement et poursuivra sa lecture en tenant compte de la substitution. Ce texte de remplacement va proc\xE9der \xE0 l'affichage des 9 premiers arguments en les s\xE9parant par une virgule, puis \TeX{} rencontrera \xE0 la fin du \idx{texte de remplacement} la macro \verb-\endlist-. Comme elle n'est suivie de rien dans le texte de remplacement, elle ira chercher son argument plus loin dans le code, et ce qu'il y a apr\xE8s justement, c'est le 10\ieme{} argument.
+
+\showcode/\def\tenlist#1#2#3#4#5#6#7#8#9{(#1,#2,#3,#4,#5,#6,#7,#8,#9\endlist}
+\def\endlist#1{,#1)}
+Une liste \tenlist abcdefghij de lettres./
+\end{exercice}
+
+Voici l'exemple de la macro \verb-\foo- que l'on a d\xE9fini pr\xE9c\xE9demment et que l'on met \xE0 l'\xE9preuve dans diff\xE9rents cas :
+
+\showcode/\def\foo#1#2{Bonjour #1 et #2.\par}
+\begingroup\tt% passer en fonte \xE0 chasse fixe\xA4\idx*\begingroup\idx*\tt\xA4
+a) \foo{monsieur}{madame}
+b) \foo{{\bf toi}}{moi}
+c) \foo{}{{}}
+d) \foo{ }{ }
+e) \foo{$\pi$} {$\delta$}
+f) \foo ab
+g) \foo X       Y
+\endgroup% fin de la fonte \xE0 chasse fixe\xA4\idx*\endgroup\xA4/
+
+\noindent Le cas b contient un argument lui-m\xEAme entre accolades, c'est-\xE0-dire dans un groupe. En effet, si les accolades int\xE9rieures n'existaient pas, cet argument serait \xAB\verb-\bf moi-\xBB et la macro \idx\bf qui ordonne le passage en fonte grasse ne serait pas contenue dans un groupe pour en limiter sa port\xE9e. Tel qu'il est \xE9crit \xE0 la ligne 4, le second argument est donc \verb-{\bf moi}- et donc le texte de remplacement de \verb-\foo{toi}{{\bf moi}}- est :
+
+\centrecode-Bonjour toi et {\bf moi}.\par-
+
+On remarque ensuite au cas c que les deux arguments ne produisent rien. Le premier parce que c'est un
+ \idx[!vide]{argument} vide et le second parce que c'est \verb-{}- qui est un groupe vide qui lui non plus ne produit non plus aucun affichage. Pour mieux comprendre ce qui se passe \xE0 cette ligne 5, le texte de remplacement de \verb-\foo{}{{}}- est :
+
+\centrecodespc-Bonjour  et {}.\par-
+
+L'argument \verb|#1|, qui est vide, se trouve entre les deux premiers espaces qui par cons\xE9quent deviennent des espaces cons\xE9cutifs, mais ils ne le sont pas \emph{dans le code source} ! La r\xE8gle de \TeX{} concernant les \idx[!cons\xE9cutifs]{espace} cons\xE9cutifs ne s'applique donc pas comme on peut l'observer \xE0 l'affichage.
+
+\begin{regle}
+Si l'argument \verb|<i>| d'une macro est vide, cela \xE9quivaudra dans le texte de remplacement de la macro \xE0 ce que \verb-#<i>- n'existe pas\idx*{argument!vide}.
+\end{regle}
+
+Le sens d'un argument \xABvide\xBB n'est pas \xE9vident. On entend ici que l'argument vide est ce qui est entre les accolades dans \xAB\verb-{}-\xBB. Si l'on pr\xE9f\xE8re, un argument vide n'est constitu\xE9 d'aucun token.
+
+Ce qui se passe au cas d est tout aussi int\xE9ressant. Les deux arguments sont des espaces \emph{entre accolades}, ils sont donc pris en compte. Le texte de remplacement est ici :
+
+\begin{centrage}
+\small\verb*-Bonjour -\fboxsep0.5pt\fbox{\ttfamily\vphantom A\textvisiblespace}\verb*- et -\fbox{\ttfamily\vphantom A\textvisiblespace}\verb-.-
+\end{centrage}
+
+\noindent Les arguments \verb-#1- et \verb-#2-, qui sont des espaces, ont \xE9t\xE9 encadr\xE9s. L'espace du code \xAB\verb*- -\xBB, suivi de l'espace qui provient de l'argument {\fboxsep0.5pt\fbox{\ttfamily\vphantom A\textvisiblespace}}, ne sont pas des espaces cons\xE9cutifs \emph{du code}. La r\xE8gle qui veut que deux espaces cons\xE9cutifs du code n'en font qu'un \emph{ne s'applique pas}. \xC0 l'affichage, on a donc \emph{trois} espaces entre \xABBonjour\xBB et \xABet\xBB puis deux entre \xABet\xBB et le point final.
+\grandsaut
+
+Lorsque \TeX{} lit le \idx{texte de param\xE8tre} puis le \idx{texte de remplacement} d'une macro pour la d\xE9finir et stocker les tokens qui r\xE9sultent de cette lecture, il entre dans ce qu'on appelle la \emph{\idx{lecture \xE0 grande vitesse}}. Tr\xE8s peu de v\xE9rifications sont faites \xE0 ce moment :
+
+\begin{enumerate}
+	\item dans le \idx{texte de param\xE8tre}, la d\xE9claration des arguments \verb|#<chiffre>| n'est accept\xE9e que si les \verb|<chiffres>| commencent \xE0 1 et vont en croissant de un en un;
+	\item une occurrence de \verb|#<chiffre>| dans le \idx{texte de remplacement}, symbolisant l'emplacement d'un argument, est accept\xE9e uniquement si cet argument a \xE9t\xE9 d\xE9clar\xE9 dans le \idx{texte de param\xE8tre};
+	\item \TeX{} v\xE9rifie que les macros rencontr\xE9es dans le \idx{texte de remplacement} ne sont pas d\xE9clar\xE9es \xAB\idx\outer\xBB (voir page~\pageref{outer});
+	\item la \idx{lecture \xE0 grande vitesse} s'arr\xEAte lorsque l'accolade ouvrante marquant le d\xE9but du \idx{texte de remplacement} est \xE9quilibr\xE9e par une accolade fermante. \xC0 ce moment, le stockage du \idx{texte de remplacement} sous forme de tokens a lieu dans la m\xE9moire de \TeX.
+\end{enumerate}
+
+L'argument d'une commande ne peut pas contenir la primitive \idx\par. Cette interdiction est en fait un m\xE9canisme de s\xE9curit\xE9 pour que, si jamais on a oubli\xE9 de fermer l'accolade qui marque la fin d'un argument, \TeX{} ne tente pas de lire ind\xE9finiment (jusqu'\xE0 la fin du document) cet argument : au premier \idx\par rencontr\xE9, la compilation est stopp\xE9e avec affichage d'un message d'erreur, ce qui limite la zone o\xF9 l'on doit chercher o\xF9 il manque une accolade fermante dans le code source. Il est parfois n\xE9cessaire de passer outre cette protection si l'on souhaite \xE9crire une macro dont un argument est susceptible de contenir \idx\par. Pour d\xE9clarer une macro de ce type, il faut faire pr\xE9c\xE9der \idx[|etc]\def\forbidindex\def{} de la primitive \idx\long. Dans ce cas, on dit que la macro est \xAB longue \xBB par opposition aux autres macros \xAB courtes \xBB.
+
+Il faut noter que si on d\xE9finit un alias pour \idx\par comme plain-\TeX{} le fait avec \verb-\let\endgraf=\par-, alors, l'alias \idx\endgraf est permis dans l'argument d'une macro m\xEAme si celle-ci n'est pas d\xE9clar\xE9e \idx\long. En effet, les arguments d'une macro sont eux aussi lus \xE0 grande vitesse\idx*{lecture \xE0 grande vitesse} avant d'\xEAtre ins\xE9r\xE9s sous forme de tokens aux endroits qui leur sont r\xE9serv\xE9s dans le texte de remplacement. Lors de cette \idx{lecture \xE0 grande vitesse}, \TeX{} ne tient pas compte de la \verb|\let| \xE9galit\xE9; il ne fait que chercher \verb|\par|. L'alias \verb|\endgraf| est parfois bien pratique puisqu'avec cet artifice, tout se passe comme si l'on pouvait mettre un \verb|\par| dans les macros courtes sans avoir besoin de les r\xE9\xE9crire pour qu'elles soient longues.
+
+\begin{regle}
+Une macro ne peut admettre la primitive \idx\par dans aucun de ses arguments. Elle admet en revanche toute \idx{s\xE9quence de contr\xF4le} \verb|\let|-\xE9quivalente \xE0 \verb|\par|, par exemple \idx\endgraf, d\xE9finie par plain-\TeX.
+
+Pour d\xE9finir une macro capable d'accepter \idx\par dans ses arguments, on doit faire pr\xE9c\xE9der \verb|\def| de la primitive \idx\long.
+\end{regle}
+
+\section{Perte d'informations lors de la \xAB tok\xE9nization \xBB}\label{perte.information.lecture}
+Examinons maintenant comment et quand sont lues les \xAB composantes \xBB d'une macro, \xE0 savoir son texte de remplacement et ses arguments, et surtout quelles sont les cons\xE9quences de cette lecture.
+
+Tout d'abord, il est utile de comprendre que plusieurs moments diff\xE9rents interviennent lorsqu'on utilise une macro :
+
+\begin{itemize}
+	\item le moment o\xF9 elle est d\xE9finie;
+	\item le (ou les) moment(s) o\xF9 elle est appel\xE9e.
+\end{itemize}
+
+\begin{regle}
+Lorsqu'une macro est \emph{d\xE9finie}, les arguments figurant dans le \idx{texte de remplacement} sous la forme \verb|#<chiffre>| (o\xF9 \xAB\verb|#|\xBB symbolise un token ayant le catcode \number\catcode`\#\relax{} au moment de la d\xE9finition) sont des endroits o\xF9 \TeX{} mettra les arguments lus plus tard lorsque la macro sera appel\xE9e.
+
+Lors de sa \idx{lecture \xE0 grande vitesse}, le reste du texte de remplacement est \xAB tok\xE9niz\xE9 \xBB c'est-\xE0-dire que les caract\xE8res composant le code source sont transform\xE9s en tokens et les catcodes qui leur sont assign\xE9s ob\xE9issent au r\xE9gime en cours lorsque la d\xE9finition a lieu. Ces tokens sont stock\xE9s dans la m\xE9moire de \TeX.
+\medskip
+
+Lorsqu'une macro est \emph{appel\xE9e} et qu'elle \emph{lit} ses arguments, ceux-ci sont lus \xE0 grande vitesse\idx*{lecture \xE0 grande vitesse} et sont tok\xE9niz\xE9s selon le r\xE9gime de catcode en vigueur cette macro est appel\xE9e (et qui peut donc diff\xE9rer de celui en cours lors de sa d\xE9finition). Ils sont ensuite ins\xE9r\xE9s aux endroits o\xF9 \verb|#<chiffre>| \xE9tait \xE9crit dans le texte de remplacement. Les tokens du \idx{texte de remplacement} ne sont pas modifi\xE9s et restent ce qu'ils \xE9taient lors de la d\xE9finition.
+\end{regle}
+
+Plus g\xE9n\xE9ralement, quels que soient le moment et les circonstances, lorsque \TeX{} lit du code source, les caract\xE8res du code source sont transform\xE9s en tokens. Cette transformation est faite selon le r\xE9gime de catcode en vigueur au moment de la lecture et des r\xE8gles sp\xE9cifiques \xE0 chaque cat\xE9gorie sont alors appliqu\xE9es. Il est important de savoir que transformer des caract\xE8res en tokens provoque d'irr\xE9versibles pertes d'informations. En voici quelques-unes :
+
+\begin{enumerate}
+	\item plusieurs \idx[!cons\xE9cutifs]{espace}s cons\xE9cutifs sont lus comme un espace unique;
+	\item les \idx[!d\xE9but de ligne]{espace}s au d\xE9but d'une ligne du code source sont ignor\xE9s ;
+	\item les espaces qui suivent une \idx{s\xE9quence de contr\xF4le} sont ignor\xE9s;
+	\item un caract\xE8re de \idx*{catcode!5 (retour charriot)}catcode 5 (en g\xE9n\xE9ral le retour charriot \xAB\verb|^^M|\xBB) est lu comme un espace\idx*[!5 (retour charriot)]\catcode\verbidx*[ (retour charriot)]{^^M};
+	\item deux caract\xE8res cons\xE9cutifs de catcode 5 sont lus comme la primitive \idx\par\verbidx*[ cons\xE9cutifs]{^^M};
+	\item deux caract\xE8res identiques de catcode \number\catcode`\^{}\idx*{catcode!7 (exposant)} (en g\xE9n\xE9ral le caract\xE8re de mise en exposant \xAB\verb|^|\xBB) suivis d'un caract\xE8re ou de deux chiffres hexad\xE9cimaux sont lus comme un caract\xE8re unique\verbidx*{^^}\iffalse i\fi;
+	\item le caract\xE8re de code \idx\endlinechar est ins\xE9r\xE9 \xE0 chaque fois qu'une \idx{fin de ligne} de code source est rencontr\xE9e ;
+	\item dans une ligne de code source, tout ce qui se trouve apr\xE8s un caract\xE8re de catcode \number\catcode`\%{} est ignor\xE9 (le caract\xE8re de commentaire est en g\xE9n\xE9ral \xAB\cidx\%\xBB).
+\end{enumerate}
+
+Par exemple, supposons qu'une macro \verb|\foo| est d\xE9finie de cette fa\xE7on sous le r\xE9gime de catcode par d\xE9faut :
+
+\centrecodespc|\def\foo{Programmer  en \TeX {} est   facile}|
+
+\noindent Par la suite, en examinant le texte de remplacement de \verb|\foo|, il est impossible de savoir combien d'espaces il y avait apr\xE8s \xAB\texttt{est}\xBB dans le code source. Il est \xE9galement impossible de savoir si \verb|\TeX| \xE9tait suivi d'un espace, de plusieurs ou d'aucun. Et donc, une fa\xE7on \emph{strictement \xE9quivalente} de d\xE9finir \verb|\foo| aurait \xE9t\xE9 :
+
+\centrecodespc|\def\foo{Program^^6der en   \TeX{} est facile}|
+
+La primitive \idx\meaning peut nous aider \xE0 le constater.
+
+\showcode|\def\foo{Programmer  en \TeX {} est   facile}
+\meaning\foo\par\xA4\idx*\meaning\xA4
+\def\foo{Program^^6der en   \TeX{} est facile}
+\meaning\foo\xA4\idx*\meaning\xA4|
+
+\begin{regle}
+Lorsque \TeX{} lit du code source, d'irr\xE9versibles pertes d'informations ont lieu lorsque des \emph{caract\xE8res} sont transform\xE9s en \emph{\idx{token}s}.
+\end{regle}
+
+Cette r\xE8gle s'applique bien \xE9videmment lorsque \TeX{} lit du code pour le stocker (que ce soit dans une macro ou dans un registre de tokens) ou pour l'ex\xE9cuter.
+
+\begin{exercice}
+Donner un autre exemple de perte d'information lorsque \TeX{} lit du code.
+\solution
+Si deux caract\xE8res ont le catcode 0\idx*{catcode!0 (caract\xE8re d'\xE9chappement)} (par exemple \xAB\verb|\|\xBB et \xAB\verb-|-\xBB), voici deux fa\xE7ons parfaitement \xE9quivalentes de d\xE9finir une macro \verb|foo| :
+
+\centrecodespc-\def\foo{Programmer en |TeX{} est facile}-
+
+\noindent et
+
+\centrecodespc-\def\foo{Programmer en \TeX{} est facile}-
+
+Si par ailleurs, "\verb|<|" et "\verb|>|" ont comme catcode 1\idx*{catcode!1 (accolade)} et 2, alors, cette fa\xE7on est \xE9galement \xE9quivalente :
+
+\centrecodespc*-\def\foo<Programmer en \TeX<> est facile}-
+
+Une autre perte d'information est que les caract\xE8res ayant un catcode \xE9gal \xE0 9 sont ignor\xE9s.
+\end{exercice}
+
+\begin{exercice}
+Comment faudrait-il s'y prendre pour que la lecture du code soit \emph{r\xE9versible}, c'est-\xE0-dire pour qu'aucune perte d'information n'ait lieu ?
+\solution
+Il faudrait que le r\xE9gime de catcode en vigueur soit tr\xE8s sp\xE9cifique et que tous les caract\xE8res ayant un catcode de 0, 1, 2, 5, 6, 9, 10, 13, 14 et 15 aient un catcode de 12. On peut aussi carr\xE9ment utiliser le r\xE9gime o\xF9 \emph{tous} les octets ont un catcode \xE9gal \xE0 12.
+\end{exercice}
+
+\section{\Qu elques commandes utiles}
+Prenons maintenant le temps de d\xE9finir des commandes utiles en programmation. Certes, il est encore t\xF4t pour comprendre leur int\xE9r\xEAt, mais nous le verrons plus tard, leur emploi est fr\xE9quent.
+
+La plus simple de toutes est pourtant tr\xE8s utile : elle lit un argument qu'elle fait disparaitre. Appelons-la\footnote{Cette macro est appel\xE9e {\ttfamily\string\@gobble} dans le noyau \LaTeX.} \xA7\gobone pour \xABgobble one\xBB qui signifie \xABmange un\xBB. Le code qui permet sa d\xE9finition est d'une simplicit\xE9 extr\xEAme :
+
+\centrecode-\def\gobone#1{}-
+
+\noindent Le texte de remplacement est vide, ce qui revient \xE0 dire que lorsque \TeX{} rencontre \verb-\gobone-, il lit \xE9galement l'argument qui suit et remplace le tout par le texte de remplacement, c'est-\xE0-dire rien.
+
+Pour rester dans la simplicit\xE9, voici une commande qui admet un argument et dont le texte de remplacement est cet argument. Appelons-la\footnote{Son nom dans le noyau \LaTeX{} est \texttt{\string\@firstofone}} \xA7\identity\label{identity} :
+
+\centrecode-\long\def\identity#1{#1}-
+
+Voici maintenant deux commandes tr\xE8s utilis\xE9es. Elles admettent deux arguments. Le texte de remplacement de \xA7\firstoftwo est son premier argument et celui \xA7\secondoftwo est son second argument\footnote{Elles sont appel\xE9es \texttt{\string\@firstoftwo} et \texttt{\string\@secondoftwo} dans le noyau \LaTeX.}\label{firstoftwo}
+
+\centrecode-\long\def\firstoftwo#1#2{#1}
+\long\def\secondoftwo#1#2{#2}\xA4\xA7*\secondoftwo\xA4-
+
+On pourrait aller plus loin et d\xE9finir, pourquoi pas, \verb|\thirdofsix| qui irait chercher le 3\ieme{} argument d'une s\xE9rie de 6 :
+
+\centrecode-\long\def\thirdofsix#1#2#3#4#5#6{#3}-
+
+\noindent Mais ces variantes sont un peu inutiles, car ce sont les macros \xA7\firstoftwo et \xA7\secondoftwo qui sont le plus souvent utilis\xE9es. Pourquoi est-il plus utile et fr\xE9quent de choisir entre \emph{deux} arguments ? L'explication tient au fait que ces macros sont utilis\xE9es apr\xE8s un test pour choisir une des alternatives, l'une correspondant au fait que le test est vrai et l'autre qu'il est faux.
+
+\begin{exercice}
+Pour manger les deux arguments \verb-{<arg1>}- et \verb-{<arg2>}-, le code suivant ne fonctionne pas :
+\centrecode-\gobone\gobone{<arg1>}{<arg2>}-
+
+Pourquoi ? Comment faudrait-il programmer la macro \xA7\gobtwo pour qu'elle mange et fasse disparaitre les deux arguments qui la suivent ?
+\solution
+\TeX{} lit le code \emph{de gauche \xE0 droite}, il remplace donc dans un premier temps \xA7\gobone et son argument, le deuxi\xE8me \xA7\gobone, par le texte de remplacement de \xA7\gobone, c'est-\xE0-dire rien. Les deux \xA7\gobone disparaissent et il reste les deux arguments entre accolades qui seront affich\xE9s tous les deux !
+
+La macro \xA7\gobtwo se programme ainsi : \verb-\def\gobtwo#1#2{}-
+\end{exercice}
+
+\begin{exercice}
+\Qu 'obtient-on \xE0 l'affichage si on \xE9crit :
+
+\centrecode-\gobone1\secondoftwo2{3\gobtwo}\firstoftwo45\secondoftwo{67}{\gobone890}\xA4\xA7*\secondoftwo\xA4-
+
+\solution
+Proc\xE9dons de gauche \xE0 droite, comme \TeX{} :
+\begin{itemize}
+	\item \xAB\verb-\gobone 1-\xBB disparait;
+	\item \xAB\verb-\secondoftwo2{3\gobtwo}-\xBB a comme texte de remplacement son 2\ieme{} argument qui est \xAB\verb-3\gobtwo-\xBB. \xAB3\xBB est donc affich\xE9 et le \verb-\gobtwo- va manger les 2 arguments qui le suivent. Ils se trouvent en dehors de l'argument en cours et ce sont \xAB\xA7\firstoftwo\verb-4-\xBB qui sont donc mang\xE9s;
+	\item \xAB5\xBB est affich\xE9;
+	\item \xAB\verb-\secondoftwo{67}{\gobone890}-\xBB a pour texte de remplacement son 2\ieme{} argument qui est \xAB\verb-\gobone890-\xBB. Le \verb|\gobone| mange le \xAB8\xBB qui disparait et il reste donc les tokens \xAB90\xBB qui seront affich\xE9s.
+\end{itemize}
+
+On obtient donc \xAB\verb-3590-\xBB
+\end{exercice}
+\begin{exercice}
+On constate que les macros \xA7\gobone et \xA7\secondoftwo donnent les m\xEAmes r\xE9sultats :
+
+\showcode/a) \gobone XY - \secondoftwo XY\par\xA4\xA7*\gobone\xA7*\secondoftwo\xA4
+b) \gobone{ab}{xy} - \secondoftwo{ab}{xy}\par
+c) \gobone{123}4 - \secondoftwo{123}4\par
+d) \gobone A{BCD} - \secondoftwo A{BCD}\xA4\xA7*\gobone\xA7*\secondoftwo\xA4/
+
+Existe-t-il une diff\xE9rence entre les macros \xA7\gobone et \xA7\secondoftwo et si oui, laquelle ?
+\solution
+Il y a une diff\xE9rence, et de taille! On peut le voir sur cet exemple :
+
+\showcode/\gobone     {a}{\catcode`\~12 Le <<~>> est un espace ?} Et ici <<~>> ?\xA4\cidx*\~\xA4
+
+\secondoftwo{a}{\catcode`\~12 Le <<~>> est un espace ?} Et ici <<~>> ?\xA4\xA7*\secondoftwo\xA4/
+
+\xC0 la premi\xE8re ligne, lorsque \xA7\gobone est d\xE9velopp\xE9e, \xAB\verb|\gobone{a}|\xBB disparait et il reste ceci qui n'a pas encore \xE9t\xE9 lu :
+
+\centrecode*-{\catcode`\~12 Le <<~>> est un espace ?} Et ici <<~>> ?-
+
+Il est clair que la modification de catcode a lieu \emph{\xE0 l'int\xE9rieur d'un groupe} et que dans ce groupe, \cidx\~ devient un caract\xE8re \xAB autre \xBB que l'on peut afficher tel quel. En revanche, une fois sorti du groupe, il reprend son catcode naturel de 13 et redevient donc actif pour afficher une espace ins\xE9cable.
+
+Tout est diff\xE9rent dans la deuxi\xE8me ligne. La macro \xA7\secondoftwo lit ses \emph{deux} arguments et \xABredonne\xBB le second une fois qu'il a \xE9t\xE9 lu. Voici donc ce qu'il reste apr\xE8s que \xA7\secondoftwo ait \xE9t\xE9 remplac\xE9 pare son 2\ieme{} argument :
+
+\begin{centrage}
+	\small\ttfamily\fboxsep2pt\fbox{\string\catcode`\string\~12 Le <{}<\string~>{}> est un espace \string?} \Verb|Et ici <<~>> ?|
+\end{centrage}
+
+Le 2\ieme{} argument, ici encadr\xE9 et qui s'\xE9tend jusqu'au premier \xAB\string?\xBB a \xE9t\xE9 lu par \xA7\secondoftwo et donc, le \idx{catcode} de \xAB\string~\xBB est fig\xE9 \xE0 13. Par cons\xE9quent, \xAB\string~\xBB gardera dans tout l'argument encadr\xE9 le \idx{catcode} 13\idx*{catcode!13 (actif)} qu'il avait lorsque \xA7\secondoftwo a \xE9t\xE9 appel\xE9. L'ordre \idx\catcode\verb|`\~12| rencontr\xE9 dans l'argument ne pourra agir qu'apr\xE8s cet argument : \cidx\~ prendra donc le \idx{catcode} 12\idx*{catcode!12 (autre)} apr\xE8s la fin de l'argument et ce en-dehors de tout groupe. Il gardera donc ce \idx{catcode} ind\xE9finiment c'est-\xE0-dire jusqu'\xE0 ce qu'il soit volontairement modifi\xE9.
+\grandsaut 
+
+Pour r\xE9sumer :
+\begin{itemize}
+	\item de \xAB\xA7\gobone\verb|{<a>}{<b>}|\xBB, il reste \verb|{<b>}|qui n'est pas encore lu;
+	\item tandis que \xA7\secondoftwo\verb|{<a>}{<b>}| lit le second argument, le d\xE9pouille de ses accolades et le tout devient donc \verb|<b>| o\xF9 les catcodes sont fig\xE9s.
+\end{itemize}
+\end{exercice}
+
+\begin{exercice}
+Le but est d'afficher l'\xE9nonc\xE9 et la correction d'une courte interrogation de grammaire \xE9l\xE9mentaire, tous deux stock\xE9s dans la macro \verb-\interro- ainsi d\xE9finie :
+
+\centrecode-\def\interro{J'ai \xE9t\?{\xE9} invit\?{\xE9} \xE0 go\xFBt\?{er} chez Max.
+             On s'est bien amus\?{\xE9} et ensuite, il a fallu
+             rentr\?{er}.}-
+
+\xC9crire une macro \verb-\?- qui admet un argument. Cet argument sera affich\xE9 tel quel si la commande \verb-\visible- a \xE9t\xE9 rencontr\xE9e auparavant, et si c'est la commande \verb-\cache-, cet argument sera remplac\xE9 par \xAB...\xBB. Les commandes \verb-\cache- et \verb-\visible- n'admettent pas d'argument.
+
+On \xE9crira \xAB\verb-\cache\interro-\xBB ou \xAB\verb-\visible\interro-\xBB selon que l'on souhaite afficher l'\xE9nonc\xE9 ou la correction.
+\solution
+L'id\xE9e est que le texte de remplacement de \verb-\?{<argument>}- doit \xEAtre
+
+\centrecode-\choix{<argument>}{...}-
+
+\noindent o\xF9 \verb-\choix- sera rendu \xE9gal \xE0 \xA7\firstoftwo par \verb-\visible- et \xE0 \xA7\secondoftwo par \verb-\cache- :
+
+\showcode/\def\visible{\let\choix=\firstoftwo}\xA4\xA7*\firstoftwo\xA4
+\def\cache{\let\choix=\secondoftwo}\xA4\xA7*\secondoftwo\xA4
+\def\?#1{\choix{#1}{...}}%
+\def\interro{J'ai \xE9t\?{\xE9} invit\?{\xE9} \xE0 gout\?{er} chez Max. Apr\xE8s s'\xEAtre
+             bien amus\?{\xE9}, nous avons rang\?{\xE9} et il a fallu rentr\?{er}.}
+Compl\xE9ter avec << \xE9 >> ou << er >> :\par
+\cache\interro\par\medskip\xA4\idx*\medskip\xA4
+Correction :\par
+\visible\interro/
+\end{exercice}
+
+\section{D\xE9finitions imbriqu\xE9es}
+\xC0 l'exercice pr\xE9c\xE9dent, on aurait pu proc\xE9der de fa\xE7on plus \xAB \xE9conomique \xBB, sans avoir besoin de d\xE9finir une macro auxiliaire \verb|\choix|. La macro \verb|\visible| aurait pu \xEAtre programm\xE9e pour d\xE9finir \verb|\?| \idx\let{}-\xE9gale \xE0 \xA7\identity (qui affiche son argument tel quel) alors que la macro \verb|\cache| aurait d\xE9fini la macro \verb|\?| de cette fa\xE7on :
+
+\centrecode-\def\?#1{...}-
+
+\noindent Mais si on \xE9crit
+
+\centrecode-\def\cache{\def\?#1{...}}-
+
+\noindent \TeX{} \xE9met un message d'erreur : \xAB\texttt{Illegal parameter number in definition of \string\cache}\xBB. L'explication est que l'argument \verb|#1| est compris comme \xE9tant celui de la macro \emph{ext\xE9rieure} \verb|\cache| et non pas comme celui de la macro int\xE9rieure \verb|\?|. L'erreur survient, car la macro ext\xE9rieure \verb|\cache| est d\xE9finie comme n'ayant \emph{aucun} argument.
+
+Lorsque des d\xE9finitions de macros sont imbriqu\xE9es, la r\xE8gle veut que pour distinguer les arguments des macros, il faut doubler les tokens de param\xE8tre \verb|#| \xE0 chaque niveau d'imbrication suppl\xE9mentaire. Ainsi, la bonne fa\xE7on de d\xE9finir \verb|\cache| est :
+
+\centrecode-\def\cache{\def\?##1{...}}-
+
+Voici le code complet :
+
+\showcode/\def\visible{\let\?=\identity}\xA4\xA7*\identity\xA4
+\def\cache{\def\?##1{...}}
+\def\interro{J'ai \xE9t\?{\xE9} invit\?{\xE9} \xE0 go\xFBt\?{er} chez Max. On s'est
+             bien amus\?{\xE9} et ensuite, il a fallu rentr\?{er}.}
+Compl\xE9ter avec << \xE9 >> ou << er >> :\par
+\cache\interro\par\medskip\xA4\idx*\medskip\xA4
+Correction :\par
+\visible\interro/
+
+\begin{regle}
+Lorsqu'on d\xE9finit une macro \xAB fille \xBB\idx*{macro fille} dans le \idx{texte de remplacement} d'une macro \xAB m\xE8re \xBB, les \verb-#- concernant les arguments de la macro fille sont doubl\xE9s, aussi bien dans le \idx{texte de param\xE8tre} que dans le \idx{texte de remplacement}.
+
+Ils seront doubl\xE9s \xE0 nouveau \xE0 chaque imbrication
+ suppl\xE9mentaire pour \xE9viter de confondre les arguments des macros imbriqu\xE9es.
+\end{regle}
+\grandsaut
+
+\xC0 la lumi\xE8re de ce qui vient d'\xEAtre dit, examinons maintenant le code suivant :
+
+\centrecodespc-\def\makemacro#1#2{\def#1##1{##1 #2}}-
+
+On constate que \verb|\makemacro| admet deux arguments et que le premier est n\xE9cessairement une \idx{s\xE9quence de contr\xF4le} puisque cet argument \verb|#1| se trouve juste apr\xE8s le \verb|\def| dans le texte de remplacement.
+
+Faisons mentalement fonctionner la macro \verb|\makemacro| lorsqu'on l'appelle de cette fa\xE7on : \verb|\makemacro\foo{BAR}|. Comme on le sait, le texte de remplacement de ce code va \xEAtre obtenu en rempla\xE7ant chaque \verb|#1| par \verb|\foo| et chaque \verb|#2| par \verb|BAR| ce qui donne :
+
+\centrecodespc-\def\foo##1{##1 BAR}- 
+
+\noindent Puisqu'on examine le code contenu dans le texte de remplacement, il devient inutile de doubler les tokens de param\xE8tre et donc, tout se passe donc comme si la macro \verb|\foo| \xE9tait d\xE9finie par :
+
+\centrecodespc-\def\foo#1{#1 BAR}-
+
+Le code obtenu ne pr\xE9sente pas de difficult\xE9 particuli\xE8re, l'argument \verb|#1| de \verb|\foo| est plac\xE9 devant l'argument \verb|#2| de \verb|\makemacro| qui est \verb|BAR|. Par exemple, si l'on \xE9crivait \xAB\verb-\makemacro\mai{mai 2014}-\xBB, alors par la suite, \verb-\mai{10}- aurait comme texte de remplacement \xAB\texttt{10 mai 2014}\xBB.
+
+\showcode/\def\makemacro#1#2{\def#1##1{##1 #2}}
+\makemacro\LL{Lamport}
+\makemacro\juin{juin 2014}
+Paris, le \juin{3}.\medbreak\xA4\idx*\medbreak\xA4
+\LL{Cher Monsieur},\smallbreak\xA4\idx*\smallbreak\xA4
+Vous \xEAtes convoqu\xE9 \xE0 un examen sur \TeX{} le \juin{21} \xE0
+9h00 pr\xE9cise dans le bureau de D. Knuth.\smallbreak\xA4\idx*\smallbreak\xA4
+Veuillez croire, \LL{Monsieur}, en mes sentiments \TeX iens./
+
+\section{Programmer un caract\xE8re actif}
+Le niveau de \TeX nicit\xE9 atteint dans cette section est plut\xF4t relev\xE9. On pourra donc, lors d'une premi\xE8re lecture, se dispenser de se plonger dans cette section, quitte \xE0 y revenir plus tard.
+\grandsaut
+
+Avant de rentrer dans le vif du sujet, rappelons ce qu'est r\xE9ellement un caract\xE8re. Aux yeux de \TeX{} lorsqu'il le lit, un caract\xE8re (c'est-\xE0-dire un token n'\xE9tant pas une \idx{s\xE9quence de contr\xF4le}) est constitu\xE9 de :
+\begin{itemize}
+	\item un code dit \xAB\idx{code de caract\xE8re}\xBB qui repr\xE9sente l'ordre du caract\xE8re dans la table des caract\xE8res. Par exemple, le caract\xE8re \xAB\verb|A|\xBB a le code de caract\xE8re \number`A{} tandis que \xAB\verb|^|\xBB a le code \number`\^. Il y a 256 codes\footnote{Pour les moteurs 8 bits, il y a effectivement 256 codes possibles. En revanche, pour les moteurs \utf, il y a en a bien plus.} possibles;
+	\item un code dit \xABcode de cat\xE9gorie\xBB ou \xABcatcode\xBB qui met le caract\xE8re dans une des 16 cat\xE9gories et lui conf\xE8re les propri\xE9t\xE9s communes \xE0 tous les caract\xE8res de cette cat\xE9gorie. Ainsi, \xAB\verb|A|\xBB a le code de cat\xE9gorie \number\catcode`A, et \xAB\verb|^|\xBB le code de cat\xE9gorie \number\catcode`\^.
+\end{itemize}
+
+Chaque caract\xE8re lu poss\xE8de donc intrins\xE8quement une \emph{paire de codes}. On peut convenir d'une notation et les mettre entre parenth\xE8ses, le premier \xE9tant le code de caract\xE8re et le second le catcode. Cela donnerait : \showcodes{A} et \showcodes^.
+\grandsaut
+
+L'objet ici est de d\xE9couvrir comment on peut programmer une macro --~appelons-la \xA7\defactive~-- qui rend actif un caract\xE8re choisi par l'utilisateur et qui lui donne un texte de remplacement donn\xE9. Ainsi, \xAB\verb-\defactive W{wagons}-\xBB fera qu'apr\xE8s cet appel, le caract\xE8re \xAB\verb|W|\xBB sera actif et son texte de remplacement sera \xABwagons\xBB.
+
+Comme nous l'avons vu, si on modifie un catcode dans le texte de remplacement d'une macro, la modification n'entrera en vigueur qu'apr\xE8s ce texte de remplacement. En effet, la r\xE8gle vue \xE0 la page~\pageref{catcode.inalterable} veut que lorsqu'un argument est lu, les catcodes des tokens qui le composent sont fig\xE9s. Il est donc exclu de programmer la macro de cette fa\xE7on
+
+\centrecode-\def\defactive#1#2{\catcode`\#1=13 \def#1{#2}}-\xA7*\defactive
+
+\noindent car, malgr\xE9 l'ordre \verb|\catcode`\#1=13|, le catcode de \verb-#1- ne serait pas modifi\xE9 \xE0 l'int\xE9rieur du texte de remplacement de \xA7\defactive. Par exemple, si \verb-#1- est \xAB\verb|W|\xBB, son catcode restera 11 (celui que \verb|W| a par d\xE9faut) et \TeX{} va \xE9chouer lorsqu'il rencontrera \verb|\def|\verb- W{wagons}-, car \xAB\verb|W|\xBB ne sera pas encore actif.
+
+\xC9videmment, on l'a vu aussi, on pourrait utiliser un \idx\gdef et agir dans un groupe o\xF9 l'on aurait d\xE9j\xE0 modifi\xE9 le catcode de \xAB\verb|W|\xBB \xE0 13. Cette m\xE9thode est possible lorsqu'on conna\xEEt \emph{\xE0 l'avance} le caract\xE8re \xE0 rendre actif. Or, ce n'est pas le cas ici puisque l'argument \verb-#1- de la macro est choisi par l'utilisateur.
+\grandsaut
+
+Int\xE9ressons-nous par exemple \xE0 la primitive \idx\lowercase{} car les fonctionnements de \idx\lowercase{} et \idx\uppercase{} sont sym\xE9triques : il suffit de comprendre comment fonctionne l'une pour comprendre comment fonctionne de l'autre.
+
+Avant d'entrer dans le vif du sujet, il faut mentionner qu'en plus du code de cat\xE9gorie et du code de caract\xE8re, chaque caract\xE8re poss\xE8de deux autres codes :
+
+\begin{itemize}
+ 	\item le \idx{code minuscule} accessible par la primitive \idx\lccode;
+ 	\item le \idx{code majuscule} accessible par la primitive \idx\uccode.
+\end{itemize}
+
+Par exemple, le code de caract\xE8re de la lettre \xABA\xBB est {\number`\A} et son code minuscule est {\number`\a} qui est celui de la lettre \xABa\xBB. Il en est ainsi pour chaque lettre majuscule de l'alphabet qui poss\xE8de un code minuscule correspondant \xE0 celui de la lettre minuscule. Gr\xE2ce \xE0 la primitive \idx\the ou \idx\number, on peut afficher les codes de caract\xE8re et les codes minuscules des lettres A, B, et m\xEAme de a, b. On va utiliser ici une macro \verb-\showcodes- pour all\xE9ger le code :
+
+\showcode/\def\showcodes#1{\string#1 : $\number`#1 \rightarrow \number\lccode`#1$}\xA4\idx*\string\idx*\number\idx*\rightarrow\idx*\the\idx*\lccode\xA4
+\showcodes A\qquad \showcodes B\qquad\xA4\idx*[|etc]\qquad\forbidindex\qquad\xA4
+\showcodes a\qquad \showcodes b\qquad \showcodes ^/
+
+On observe que logiquement, le \idx{code minuscule} de \xABa\xBB est le sien propre. \Qu ant au code minuscule de \xAB\verb|^|\xBB, il est \xE9gal \xE0 0 ce qui signifie que ce caract\xE8re n'a pas de code minuscule pr\xE9d\xE9fini.
+
+\begin{regle}
+La primitive \idx\lowercase doit \xEAtre suivie de son argument entre accolades et cet argument, constitu\xE9 d'un texte dont les accolades sont \xE9quilibr\xE9es, est lu de la fa\xE7on suivante :
+
+\begin{itemize}
+	\item les s\xE9quences de contr\xF4les restent inchang\xE9es;
+	\item pour chaque caract\xE8re, le code de caract\xE8re est remplac\xE9 par le \idx{code minuscule}, \xE9tant entendu que le code de cat\xE9gorie \emph{ne change pas}.
+	
+	Si le code minuscule d'un caract\xE8re est nul, ce caract\xE8re n'est pas modifi\xE9 par \idx\lowercase.
+\end{itemize}
+\end{regle}
+
+Voici la primitive \idx\lowercase en action :
+
+\showcode/\lowercase{CACAO foobar}\par\xA4\idx*\lowercase\xA4
+\lowercase{\def\foo{Bonjour}}% d\xE9finit une commande \foo
+\foo % la commande d\xE9finie pr\xE9c\xE9demment/
+
+On peut d\xE9tourner la primitive \idx\lowercase de son usage premier qui est de mettre un texte en minuscule. Pour cela, il suffit de modifier le code minuscule d'un caract\xE8re. Supposons que nous souhaitions que le \idx{code minuscule} de \xABA\xBB ne soit plus {\number`\a} qui est celui de la lettre \xABa\xBB, mais {\number`\*} qui est celui de \xAB\verb-*-\xBB. Pour cela, il va falloir modifier le \idx\lccode de \xABA\xBB \xE0 l'int\xE9rieur d'un groupe semi-simple, puisqu'il est toujours prudent de confiner les modifications lorsqu'on touche aux m\xE9canismes internes de \TeX{} :
+
+\showcode/\begingroup\xA4\idx*\begingroup\xA4
+	\lccode`A=`* % change le code minuscule de A\xA4\idx*\lccode\xA4
+	\lowercase{CACAO ABRACADABRA}\par\xA4\idx*\lowercase\xA4
+\endgroup\xA4\idx*\endgroup\xA4
+\lowercase{CACAO ABRACADABRA}/
+
+Les \xAB*\xBB que l'on obtient ont le catcode de A, c'est-\xE0-dire 11.
+
+\begin{regle}
+Si l'on \xE9crit \xAB\verb|\lccode<entier1>=<entier2>|\xBB alors, dans l'argument de \verb|\lowercase|, tous les caract\xE8res de code \verb|<entier1>| seront lus comme des caract\xE8res de code \verb|<entier2>| tout en gardant leur catcode originel.
+
+En pratique, si l'on \xE9crit
+
+\centrecode-\lccode`\<car1>=`\<car2>-
+
+puis
+
+\centrecode-\lowercase{<texte>}-
+
+alors, dans le \verb|<texte>|, tous les \verb|<car1>| sont lus comme \verb|<car2>|, mais en conservant le catcode de \verb|<car1>|.
+\end{regle}
+
+Nous sommes pr\xEAts pour \xE9crire la macro \xA7\defactive et nous allons exploiter le fait que le caract\xE8re \xAB\cidx\~\xBB est naturellement actif. Gr\xE2ce \xE0 la primitive \idx\lowercase, on va le transformer dynamiquement pour qu'il devienne le caract\xE8re \verb-#1- \emph{actif} de notre macro \xA7\defactive :
+
+\centrecode|\def\defactive#1#2{%\xA4\xA7*\defactive\xA4
+    \catcode`#1=13 % #1 sera actif apr\xE8s la fin
+                   % du texte de remplacement
+    \begingroup
+    \lccode`~=`#1  % dans \lowercase, changer les ~ (actifs)
+                   % en "#1", ceux-ci \xE9tant actifs
+    \lowercase{\endgroup\def~}{#2}%
+}|
+
+\begin{itemize}
+	\item \xAB\idx\catcode\verb|`#1=13|\xBB\idx*[!13 (actif)]\catcode rend le caract\xE8re \verb-#1- actif, mais comme nous l'avons vu, cette modification n'entrera en vigueur qu'apr\xE8s \xEAtre sorti du texte de remplacement;
+    \item Le \idx\endgroup n'\xE9tant pas modifi\xE9 par \idx\lowercase, le groupe semi-simple est donc bien referm\xE9 \emph{avant} d'effectuer la d\xE9finition de \verb-#1-;
+	\item on peut remarquer que l'argument \verb-#2- se trouve \emph{en dehors} de l'argument de \idx\lowercase car sinon, toutes les lettres majuscules de \verb|#2| seraient transform\xE9es en minuscules.
+	
+	D'ailleurs, comme \verb-{#2}- est \xE0 la fin du texte de remplacement de la macro, il devient inutile de le lire puisqu'il sera lu juste apr\xE8s. On peut optimiser la macro de cette fa\xE7on\label{argument.def} :
+	
+	\centrecode-\def\defactive#1{%\xA4\xA7*\defactive\xA4
+	\catcode`#1=13
+	\begingroup
+	\lccode`~=`#1
+	\lowercase{\endgroup\def~}}-
+\end{itemize}
+
+Voyons cette macro \xE0 l'\oe uvre dans un exemple :
+
+\showcode/\def\defactive#1{%\xA4\xA7*\defactive\xA4
+	\catcode`#1=13
+	\begingroup
+	\lccode`~=`#1
+	\lowercase{\endgroup\def~}%
+}
+\begingroup% les modifications restent locales\xA4\idx*\begingroup\xA4
+	\defactive W{wagons}% d\xE9finit le caract\xE8re actif "W"\xA4\xA7*\defactive\xA4
+	Les W constituent les trains.
+\endgroup %fermeture du groupe, "W" redevient une lettre\xA4\idx*\endgroup\xA4
+\par Les W sont des lettres/
+
+\begin{exercice}
+Supposons que \xAB\verb-W-\xBB soit rendu actif \xE0 l'aide de la macro \xA7\defactive pour lui donner le texte de remplacement \xABwagons\xBB. Imaginons ensuite que l'on rende \xAB\verb|W|\xBB non actif avec \idx\catcode\verb-`\W=11-.
+
+\Qu estion : si l'on rend \xE0 nouveau \verb|W| actif, le texte de remplacement pr\xE9c\xE9demment d\xE9fini existe-t-il encore ou faut-il red\xE9finir son texte de remplacement ?
+\solution
+Il suffit de faire l'exp\xE9rience :
+
+\showcode/\defactive W{wagon}\xA4\xA7*\defactive\xA4
+1) Les W constituent le train.\par
+2) \catcode`W=11 Les W sont des lettres.\par\xA4\idx*\catcode\xA4
+3) \catcode`\W=13 Les W constituent-ils le train ?/
+
+La r\xE9ponse est donc \xAB oui \xBB.
+
+Le \idx[!caract\xE8re actif]{texte de remplacement} d'un caract\xE8re actif n'est pas perdu si ce caract\xE8re change de catcode et redevient actif ensuite.
+\end{exercice}
+
+\begin{exercice}
+D\xE9crire ce qui va se passer si on d\xE9finit le caract\xE8re actif \xAB\verb|W|\xBB de la fa\xE7on suivante :
+\centrecode-\defactive W{Wagon}-
+
+\solution
+Tout d\xE9pend de la version de \xA7\defactive. La r\xE9ponse est tr\xE8s diff\xE9rente selon que \xA7\defactive lit 1 ou 2 arguments, c'est-\xE0-dire si elle lit le texte de remplacement du caract\xE8re actif ou pas.
+
+Si elle le lit, le \xAB\verb|W|\xBB de \xAB\verb|Wagon|\xBB aura le catcode en vigueur au moment ou \xA7\defactive lit son argument, c'est-\xE0-dire 11\idx*{catcode!11 (lettre)}. Le texte de remplacement de \xAB\verb|W|\xBB sera \xAB\verb|Wagon|\xBB o\xF9 toutes les lettres ont le catcode 11.
+
+\showcode|\def\defactive#1#2{%\xA4\xA7*\defactive\xA4
+	\catcode`#1=13 % #1 sera actif apr\xE8s la fin du texte de remplacement
+	\begingroup
+	\lccode`~=`#1  % dans \lowercase, changer les ~ (actifs) en "#1", ceux-ci \xE9tant actifs
+	\lowercase{\endgroup\def~}{#2}%
+	}
+\defactive W{Wagon}
+Un W.|
+
+Si \xA7\defactive ne lit pas le texte de remplacement (version \xABoptimis\xE9e\xBB), le caract\xE8re \xAB\verb|W|\xBB sera actif \xE0 la fin du texte de remplacement et donc, lorsque \verb|\def W| lira le texte de remplacement entre accolades, le \xAB\verb|W|\xBB de \xAB\verb|Wagon|\xBB sera actif. On entrevoit ce qui va se passer lorsque \verb|W| sera ex\xE9cut\xE9. Dans un premier temps, \verb|W| va \xEAtre remplac\xE9 dans la \idx{pile d'entr\xE9e} par
+
+\centrecode-Wagon-
+
+puis le premier \xAB\verb|W|\xBB, actif, sera ex\xE9cut\xE9 et donc, nous aurons dans la \idx{pile d'entr\xE9e}
+
+\centrecode-Wagonagon-
+
+Le \verb|W| actif g\xE9n\xE9r\xE9 sera \xE0 nouveau ex\xE9cut\xE9 et ainsi de suite\ldots{} Une \idx{boucle infinie} va s'amorcer au cours de laquelle les caract\xE8res \xAB\verb|agon|\xBB seront ajout\xE9s sur la \idx{pile d'entr\xE9e} \xE0 chaque boucle, provoquant rapidement le d\xE9passement de sa capacit\xE9 et g\xE9n\xE9rant le message d'erreur
+
+\errcode|\def\defactive#1{%\xA4\xA7*\defactive\xA4
+	\catcode`#1=13 % #1 sera actif apr\xE8s la fin du texte de remplacement
+	\begingroup
+	\lccode`~=`#1 % dans \lowercase, changer les ~ (actifs) en "#1", ceux-ci \xE9tant actifs
+	\lowercase{\endgroup\def~}%
+	}
+\defactive W{Wagon}
+Un W.|{\ttfamily ! TeX capacity exceeded, sorry [input stack size=5000]}
+
+La morale que l'on peut retirer de cet exercice est qu'une \xAB optimisation \xBB, qui de prime abord peut sembler anodine (ne pas faire lire un argument par une macro), conduit \xE0 des limitations et \xE0 des erreurs de compilation qui n'existaient pas dans une version \xAB non optimis\xE9e \xBB. La programmation en \TeX{} est pav\xE9e d'embuches\ldots{} Il est donc n\xE9cessaire de parfaitement savoir ce que l'on fait, de connaitre le r\xE9gime de catcodes en cours lorsqu'une lecture est faite et toujours rester vigilant d\xE8s lors qu'il est question de lecture d'argument.
+\end{exercice}
+
+Les man\oe uvres d\xE9crites dans cette section reposent sur la supposition que \xAB\cidx\~\xBB est actif lorsque la macro \xA7\defactive est \emph{d\xE9finie}. Si ce n'est pas la cas et si, pour une raison ou pour une autre, \xAB\cidx\~\xBB a \xE9t\xE9 neutralis\xE9 et mis dans la cat\xE9gorie des caract\xE8res \xAB autres \xBB de catcode 12\idx*{catcode!12 (autre)}, la macro \xA7\defactive ne pourra et provoquera une erreur de compilation lors de son ex\xE9cution.
+\grandsaut
+
+Tout ce qui a \xE9t\xE9 dit avec les primitives \idx\lowercase et \idx\lccode est valable pour leurs sym\xE9triques, les primitives \idx\uppercase et \idx\uccode qui agissent sur le \xAB \idx{code majuscule} \xBB d'un caract\xE8re. On aurait d'ailleurs tout aussi bien pu proc\xE9der avec \idx\uppercase et \idx\uccode.
+
+\showcode|\def\defactive#1#2{%\xA4\xA7*\defactive\xA4
+	\catcode`#1=13 % #1 sera actif apr\xE8s la fin du texte de remplacement
+	\begingroup
+	\uccode`~=`#1 % dans \uppercase, changer les ~ (actifs) en "#1", ceux-ci \xE9tant actifs\xA4\idx*\uccode\xA4
+	\uppercase{\endgroup\def~}{#2}%\xA4\idx*\uppercase\xA4
+}
+\defactive W{Wagon}
+Un W.|
+
+Une macro \xE0 peu pr\xE8s similaire \xA7\letactive\verb|<token><token>| est facile \xE0 programmer :
+
+\showcode|\def\letactive#1{%\xA4\xA7*\letactive\xA4
+	\catcode`#1=13 % #1 sera actif apr\xE8s la fin du texte de remplacement
+	\begingroup
+	\uccode`~=`#1 % dans \uppercase, changer les ~ (actifs) en "#1", ceux-ci \xE9tant actifs\xA4\idx*\uccode\xA4
+	\uppercase{\endgroup\let~}%\xA4\idx*\uppercase\xA4
+}
+\def\W{wagon}%
+\letactive X\W\xA4\xA7*\letactive\xA4
+Un X.|
+
+\section{Afficher du code tel qu'il a \xE9t\xE9 \xE9crit}\label{litterate}\idx*[|(]{verbatim}
+Le but est d'inventer une commande qui d\xE9sactive toutes les r\xE8gles de \TeX{} pour que son argument soit affich\xE9 tel qu'il a \xE9t\xE9 \xE9crit dans le code source, ce que l'on appelle du \xABverbatim\xBB. Cette commande \xAB \xA7\litterate \xBB va donc rendre inoffensifs tous les tokens de catcode autre que 11 ou 12, en changeant leur catcode pour 12. Ces tokens \emph{sp\xE9ciaux} sont \boxtoken[]\textvisiblespace, \boxtoken[]\textbackslash, \boxtoken[]\{, \boxtoken[]\}, \boxtoken[]\$, \boxtoken[]\&, \boxtoken[]\#, \boxtoken[]{\char`\$}, \boxtoken[]\_, \boxtoken[]\% et \boxtoken[]{\char`\~}. Plain-\TeX{} d\xE9finit\footnote{En plain-\TeX, les tokens \texttt{\string^\string^K} et  \texttt{\string^\string^A} sont des \xE9quivalents pour \xAB\texttt{\string^}\xBB et \xAB\texttt{\string_}\xBB.} la macro \idx\dospecials de cette fa\xE7on :
+
+\indentcode[7em]-\def\dospecials{\do\ \do\\\do\{\do\}\do\$\do\&%
+  \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~}-
+
+La macro \idx\do peut \xEAtre programm\xE9e comme on l'entend pour agir sur son argument. Ici, comme le but est de changer le catcode de cet argument pour 12, on va donc la programmer ainsi :
+
+\centrecode-\def\do#1{\catcode`#1=12 }-
+
+\noindent et il suffira d'appeler \idx\dospecials pour qu'\xE0 partir de ce moment, tous les tokens sp\xE9ciaux soient inoffensifs et deviennent affichables.
+
+En ce qui concerne la syntaxe de \xA7\litterate, il serait l\xE9gitime d'\xE9crire son argument entre accolades, mais cela rendrait la t\xE2che compliqu\xE9e. En effet, cette macro doit rendre tous les tokens sp\xE9ciaux inoffensifs \emph{avant} de lire son argument. Par cons\xE9quent, les accolades d\xE9limitant l'argument ne seraient pas de \emph{vraies} accolades de catcode 1\idx*{catcode!1 (accolade)} et 2, mais des accolades de catcode 12\idx*{catcode!12 (autre)}. Pour savoir o\xF9 se situe la fin de l'argument, il faudrait parcourir le code qui se trouve apr\xE8s \xA7\litterate token par token, compter les accolades ouvrantes et fermantes jusqu'\xE0 obtenir l'\xE9galit\xE9 entre ces deux quantit\xE9s qui signifierait la fin de l'argument. C'est faisable, mais inutilement compliqu\xE9 et implique comme limitation que le code \xE0 afficher soit \xE9quilibr\xE9 en accolades ouvrantes et fermantes. Le mieux est de d\xE9cider \xE0 chaque fois d'un token (de catcode 11\idx*{catcode!11 (lettre)} ou 12\idx*{catcode!12 (autre)}) et de placer l'argument entre deux occurrences de ce token\footnote{C'est la syntaxe adopt\xE9e par la macro \texttt{\string\verb} de \LaTeX.}. On peut par exemple \xE9crire
+
+\centrecode-\litterate|\foo # #34{ ~} &_\ |-
+
+\noindent et obtenir l'affichage \xAB\verb|\foo # #34{ ~} &_\ |\xBB. La limitation \xE9vidente est que le token choisi comme d\xE9limiteur ne doit pas figurer dans l'argument.
+
+Du c\xF4t\xE9 de la programmation, la macro \xA7\litterate doit ouvrir un groupe semi-simple puis rendre les tokens sp\xE9ciaux inoffensifs. \xC0 l'aide de la macro \xA7\defactive vue \xE0 la section pr\xE9c\xE9dente, elle doit aussi rendre actif le retour \xE0 la ligne \xAB\verb-^^M-\verbidx*[ (retour charriot)]{^^M}\xBB et lui donner comme texte de remplacement \idx\par\idx\leavevmode. Le \idx\leavevmode, en quittant le mode vertical\idx*{mode!vertical} mis en place par \idx\par{}, entre dans le mode horizontal\idx*{mode!horizontal} et commence un nouveau paragraphe. Sans ce \idx\leavevmode, deux retours \xE0 la ligne cons\xE9cutifs seraient \xE9quivalents \xE0 deux \idx[!cons\xE9cutifs]\par et le second serait ignor\xE9 (voir r\xE8gle page~\pageref{par.consecutifs}). De plus, le token fronti\xE8re choisi doit aussi \xEAtre rendu actif et pour devenir \idx\let-\xE9gal \xE0 \idx\endgroup; ainsi, lorsque le second token fronti\xE8re sera rencontr\xE9, le groupe semi-simple sera ferm\xE9 et tous les catcodes seront restaur\xE9s comme avant que la macro \xA7\litterate n'entre en action.
+
+\showcode|\def\litterate#1{% #1=lit le token fronti\xE8re choisi\xA4\xA7*\litterate\xA4
+	\begingroup% ouvre un groupe pour y faire les modifications\xA4\idx*\begingroup\xA4
+		\def\do##1{\catcode`##1=12 }% \do change le catcode de son argument \xE0 12\xA4\idx*\do\idx*\catcode\xA4
+		\dospecials% rend inoffensifs tous les tokens sp\xE9ciaux\xA4\idx*\dospecials\xA4
+		\defactive\^^M{\leavevmode\par}% d\xE9finit le retour charriot\xA4\xA7*\defactive\idx*\leavevmode\xA4
+		\letactive#1\endgroup% d\xE9finit #1 qui sera un \endgroup\xA4\xA7*\letactive\xA4
+		\tt% passe en fonte \xE0 chasse fixe\xA4\idx*\tt\xA4
+}
+essai 1 : \litterate*\foo # #34{ \xA4\%\xA4} &_\ *
+\medbreak\xA4\idx*\medbreak\xA4
+essai 2 : \litterate/une premi\xE8re ligne  ,, >>
+
+un saut de ligne et la seconde --/|
+
+L'ensemble fonctionne bien \xE0 part les espaces qui sont rendus avec le mauvais caract\xE8re et les certaines \idx{ligature}s qui sont faites \xE0 l'essai \no2.
+
+Pour l'espace tout d'abord, cela s'explique car son catcode a \xE9t\xE9 rendu \xE9gal \xE0 12 par \idx\dospecials et le caract\xE8re \xAB\verb*| |\xBB se trouve \xE0 la position de l'espace dans la \idx{fonte} \xE0 chasse fixe. Pour contourner ce probl\xE8me, il faut rendre l'espace actif apr\xE8s l'appel \xE0 \idx\dospecials et lui donner comme texte de remplacement la primitive \idx\ {}.
+
+Ensuite, pour les \idx{ligature}s, il faut d\xE9j\xE0 identifier quels sont les caract\xE8res doubl\xE9s qui forment une \idx{ligature} en fonte \xE0 chasse fixe. Ces caract\xE8res sont : \boxtoken{`}, \boxtoken{<}, \boxtoken{>}, \boxtoken{,}, \boxtoken{'} et \boxtoken{-}. Pour \xE9viter qu'ils ne forment une \idx{ligature}, il va falloir les rendre actifs et les faire suivre soit de \xAB\verb|{}|\xBB, soit de \idx\relax soit encore de \idx\kern\verb|0pt|, ou plus g\xE9n\xE9ralement de quelque chose ne se traduisant par aucun affichage. Ainsi, ils sembleront se suivre \xE0 l'affichage, mais aux yeux de \TeX{}, ils seront s\xE9par\xE9s par un n\oe ud\footnote{Un n\oe ud est un \xE9l\xE9ment, visible ou pas, qui entre dans la liste horizontale ou verticale que \TeX{} est en train de construire.} qui emp\xEAchera la formation de la \idx{ligature}.
+
+\showcode|\def\litterate#1{% #1=lit le token fronti\xE8re choisi\xA4\xA7*\litterate\xA4
+	\begingroup% ouvre un groupe pour y faire les modifications\xA4\idx*\begingroup\xA4
+		\def\do##1{\catcode`##1=12 }% \do change le catcode de son argument \xE0 12\xA4\idx*\do\idx*\catcode\xA4
+		\dospecials% rend inoffensifs tous les tokens sp\xE9ciaux\xA4\idx*\dospecials\xA4
+		\defactive\^^M{\leavevmode\par}% d\xE9finit le retour charriot\xA4\idx*\leavevmode\xA7*\defactive\xA4
+		\defactive\ {\ }% l'espace est actif et devient "\ "
+		\defactive<{\string<{}}\defactive>{\string>{}}% emp\xEAche\xA4\idx*\string\xA4
+		\defactive-{\string-{}}\defactive`{\string`{}}% les
+		\defactive,{\string,{}}\defactive'{\string'{}}% ligatures\xA4\idx*{ligature}\idx*\string\xA7*\defactive\xA4
+		\letactive#1\endgroup% #1 sera un \endgroup\xA4\xA7*\letactive\xA4
+		\tt% passe en fonte \xE0 chasse fixe\xA4\idx*\tt\xA4
+}
+essai 1 : \litterate*\foo # #34{ %} &_\ *
+\medbreak\xA4\idx*\medbreak\xA4
+essai 2 : \litterate/une premi\xE8re      ligne  ,, >>
+
+un saut de ligne et la seconde --/\xA4\xA7*\litterate\xA4|\idx*[|)]{verbatim}
+
+\chapter{Arguments d\xE9limit\xE9s}\idx*[|(]{argument!d\xE9limit\xE9}
+\section{Th\xE9orie}\label{theorie}
+Les commandes que l'on d\xE9finit avec \verb|\def| peuvent \xE9galement avoir des \xABarguments d\xE9limit\xE9s\xBB. Ces arguments-l\xE0 ne sont pas lus de la m\xEAme fa\xE7on que les arguments \xABnon d\xE9limit\xE9s\xBB que nous avons vus pr\xE9c\xE9demment. On indique \xE0 \TeX{} qu'une macro a un ou des arguments d\xE9limit\xE9s lorsque son \idx{texte de param\xE8tre} contient d'autres unit\xE9s lexicales que \verb-#-$i$ o\xF9 $i$ est un entier de 1 \xE0 9. Ces unit\xE9s lexicales sont appel\xE9es les d\xE9limiteurs.
+
+\begin{regle}
+Un argument \verb-#<-$i$\verb|>| est dit \xABd\xE9limit\xE9\xBB si, dans le \idx{texte de param\xE8tre}, il est suivi par autre chose que \hbox{\verb-#<-$i$+1\verb|>|} ou que l'accolade \xAB\cidx\{\xBB qui marque le d\xE9but du \idx{texte de remplacement}.
+\end{regle}
+
+Voici un exemple :
+\centrecode-\def\foo.#1**#2#3/{Bonjour #1, #2 et #3}-
+
+\noindent Ici, \verb-#1- et \verb-#3- sont les arguments d\xE9limit\xE9s puisqu'ils sont suivis par respectivement \xAB\verb-**-\xBB et \xAB\verb-/-\xBB. Par la suite, lorsque \TeX{} va ex\xE9cuter \verb-\foo-, il s'attendra \xE0 ce qu'elle soit imm\xE9diatement suivie de \xAB\verb-.-\xBB puis de quelque chose (qui sera l'argument \verb-#1-) qui s'\xE9tendra jusqu'\xE0 la premi\xE8re occurrence de \xAB\verb-**-\xBB, puis autre chose (qui deviendra les arguments \verb-#2#3-) qui s'\xE9tendra jusqu'\xE0 la premi\xE8re occurrence de \xAB\verb-/-\xBB. Ayant d\xE9fini la commande  \verb-\foo- avec le code pr\xE9c\xE9dent, supposons que l'on \xE9crive :
+\centrecode-\foo.ab{123}c**xyz/-
+
+\noindent Dans ce cas, \verb-#1- sera \xAB\verb*-ab{123}c-\xBB. \Qu ant aux tokens \xABxyz\xBB, ils sont \xE0 r\xE9partir entre \verb-#2- et \verb-#3- selon la r\xE8gle suivante :
+
+\begin{regle}
+Lorsqu'une macro est ex\xE9cut\xE9e et qu'elle doit lire une suite de $n$ arguments dont le dernier est d\xE9limit\xE9, les $n-1$ premiers arguments sont assign\xE9s comme des arguments non d\xE9limit\xE9s. Le dernier argument re\xE7oit ce qui reste jusqu'au d\xE9limiteur, ceci \xE9tant \xE9ventuellement vide.
+\end{regle}
+
+D'apr\xE8s cette r\xE8gle, l'argument \verb-#2- de l'exemple pr\xE9c\xE9dent n'est pas d\xE9limit\xE9 et sera \xAB\verb|x|\xBB. L'argument \verb-#3- qui est d\xE9limit\xE9 sera donc qu'il reste jusqu'au d\xE9limiteur \xAB\verb|/|\xBB c'est-\xE0-dire \xAB\verb|yz|\xBB. Le texte de remplacement sera donc :
+\centrecode-Bonjour ab123c, x et yz.-
+
+\begin{regle}
+Dans tous les cas, qu'il soit d\xE9limit\xE9 ou pas, si un argument est de la forme \verb-{<tokens>}-, o\xF9 \verb-<tokens>- est un ensemble d'unit\xE9s lexicales o\xF9 les accolades sont \xE9quilibr\xE9es, alors \TeX{} \emph{supprime les accolades ext\xE9rieures} et l'argument lu est \xAB\verb-<tokens>-\xBB.\idx*{argument!suppression d'accolades}
+\end{regle}
+
+Un cas particulier de cette r\xE8gle engendre une autre r\xE8gle :
+
+\begin{regle}
+Un argument d\xE9limit\xE9 est vide si l'ensemble des tokens qui lui correspond est vide ou \xAB\verb-{}-\xBB.\idx*{argument!vide}%
+\end{regle}
+
+Ainsi, si on d\xE9finit la macro \verb|\bar| ainsi :
+
+\centrecode-\def\bar#1#2#3+{L'argument d\xE9limit\xE9 est : "#3".}-
+
+\noindent Alors, l'argument \verb|#3| est vide dans ces deux cas :
+\begin{itemize}
+	\item \xAB\verb-\bar{123}x+-\xBB car \xAB\verb|123|\xBB et \xAB\verb|x|\xBB sont les 2 premiers arguments et il ne reste rien pour le troisi\xE8me;
+	\item \xAB\verb-\bar{a}{b}{}+-\xBB car \verb|#3| re\xE7oit \xAB\verb|{}|\xBB.
+\end{itemize}
+En revanche, si on avait \xE9crit \verb-\bar{a}{b}{}{}+-, l'argument d\xE9limit\xE9 aurait \xE9t\xE9 \xAB\verb-{}{}-\xBB ce qui n'est pas un argument vide.
+\grandsaut
+
+Plut\xF4t que d'envisager un par un de nombreux cas, voici un tableau qui affiche ce que seraient les arguments \verb-#1-, \verb-#2- et \verb-#3- dans plusieurs cas de figure avec la d\xE9finition de \verb-\foo- rappel\xE9e en haut du tableau :
+
+\begin{centrage}
+\small
+\makeatletter
+\def\fooa.#1**#2#3/{\textvide#1|}
+\def\foob.#1**#2#3/{\textvide#2|}
+\def\fooc.#1**#2#3/{\textvide#3|}
+\def\textvide#1|{%
+	\ifx_#1_<vide>%
+	\else\ttfamily{\everyeof{\relax}\endlinechar\m at ne\catcode`\{=12 \catcode`\}=12 \catcode32=12 \scantokens{#1\relax}}%
+	\fi}
+\makeatother
+
+\makeatother
+\tabcolsep1em
+\begin{tabular}{lccc}
+\multicolumn4c{\ttfamily\string\def\string\foo.\#1**\#2\#3/\{...\}}\\[1ex]\hline
+ & \ttfamily\#1 & \ttfamily\#2 & \ttfamily\#3\\\hline
+1. \verb*-\foo. abc**123/-& \fooa. abc**123/ & \foob. abc**123/ & \fooc. abc**123/\\
+2. \verb*-\foo.**k/-&\fooa.**k/&\foob.**k/&\fooc.**k/\\
+3. \verb*-\foo.1{**}2**{ab}{cd}/-&\fooa.1{**}2**{ab}{cd}e/&\foob.1{**}2**{ab}{cd}e/&\fooc.1{**}2**{ab}{cd}/\\
+4. \verb*-\foo.{ab}**1{cd} /-&\fooa.{ab}**1{cd} /&\foob.{ab}**1{cd} /&\fooc.{ab}**1{cd} /\\
+5. \verb*-\foo. **xy/-&\fooa. **xy/&\foob. **xy/&\fooc. **xy/\\
+6. \verb*-\foo.xy** z/-&\fooa.xy** z/&\foob.xy** z/&\fooc.xy** z/\\
+7. \verb*-\foo.xy** /-&\multicolumn3c{<Erreur de compilation>}\\
+8. \verb*-\foo**/-&\multicolumn3c{<Erreur de compilation>}\\\hline
+\end{tabular}
+\end{centrage}
+\noindent Voici maintenant quelques observations :
+\begin{itemize}
+	\item la ligne 1 met en \xE9vidence que \verb-#1- r\xE9colte ce qui est entre \xAB\verb-.-\xBB et \xAB\verb-**-\xBB, espaces compris ;
+	\item on observe \xE0 la ligne 2 que le \xAB\verb-.-\xBB est imm\xE9diatement suivi du d\xE9limiteur \xAB\verb-**-\xBB et donc, l'argument d\xE9limit\xE9 \verb-#1- est vide\idx*{argument!vide}. L'argument \verb-#3-, qui est d\xE9limit\xE9, est vide puisqu'il ne reste rien apr\xE8s \verb-#2- qui est \xABk\xBB;
+	\item la ligne 3 montre que si le d\xE9limiteur \xAB\verb-**-\xBB est entre accolades, il n'est pas reconnu comme d\xE9limiteur et ne stoppe pas la lecture de l'argument \verb-#1-;
+	\item \xE0 la ligne 4, l'argument d\xE9limit\xE9 \verb-#1- est \xAB\verb-{ab}-\xBB et comme cet argument est un texte entre accolades, les accolades sont supprim\xE9es lors de la lecture de cet argument\idx*{argument!suppression d'accolades}. Par contre, l'autre argument d\xE9limit\xE9 \verb-#3- est \xAB\verb*-{cd} -\xBB et lui n'est pas r\xE9duit \xE0 un texte entre accolades, il y a l'espace en plus. Les accolades ne sont donc pas supprim\xE9es ;
+	\item \xE0 la ligne 6, on peut se demander pour quelle raison \verb-#2- n'est pas \xAB\verb*- -\xBB et \verb-#3- n'est pas \xAB\verb-z-\xBB. En fait, l'argument non d\xE9limit\xE9 \verb-#2- cherche son assignation dans \xAB\verb*- z-\xBB et comme on l'a vu au chapitre pr\xE9c\xE9dent, un espace est ignor\xE9 dans une liste d'arguments non d\xE9limit\xE9s\idx*{argument!espace}. Donc \verb-#2- devient \xAB\verb-z-\xBB, ce qui explique pourquoi l'argument d\xE9limit\xE9 \verb-#3- est vide puisqu'il ne reste plus rien entre la fin de \verb-#2- et le d\xE9limiteur \xAB\verb|/|\xBB
+	\item l'erreur qui survient \xE0 la ligne 7 est due \xE0 l'argument non d\xE9limit\xE9 \verb-#2- qui cherche son assignation dans \xAB\verb*- /-\xBB. Ignorant l'espace, \verb-#2- devient \xAB\verb|/|\xBB et capture le d\xE9limiteur qui ne sera plus vu par \verb-\foo-. \TeX{} va donc lire du code jusqu'\xE0 ce qu'il rencontre une autre \xAB\verb|/|\xBB, ce qui est peu probable et qui, si cela arrivait, donnerait un argument \verb-#3- beaucoup plus \xE9tendu que pr\xE9vu. Si \TeX{} ne trouve pas d'autre \xAB\verb|/|\xBB, la lecture peut se poursuivre jusqu'\xE0 ce qu'il arrive sur un \idx\par et comme la macro n'est pas d\xE9clar\xE9e \idx\long, il va se plaindre d'un \xAB{\ttfamily Paragraph ended before \verb-\foo- was complete}\xBB\footnote{Le paragraphe s'est termin\xE9 avant que la lecture de \texttt{\string\foo} n'ait \xE9t\xE9 achev\xE9e.}. Si l'on est proche de la fin du fichier, \TeX{} peut m\xEAme vainement chercher son d\xE9limiteur \xAB\verb|/|\xBB jusqu'\xE0 la fin du fichier et \xE9mettre un \xAB{\ttfamily File ended while scanning use of \verb-\foo-}\xBB\footnote{Fichier termin\xE9 pendant la lecture de \texttt{\string\foo}.}.
+	\item \xE0 la ligne 8, ce qui suit la commande \verb-\foo- n'est pas \xAB\verb-.-\xBB donc \TeX{} nous informe que ce qu'il trouve ne correspond pas \xE0 ce qu'il attend avec un \xAB\texttt{Use of \string\foo{} doesn't match its definition}\xBB\footnote{L'emploi de {\ttfamily\string\foo} ne correspond  pas \xE0 sa d\xE9finition.}.
+\end{itemize}
+
+\begin{exercice}
+Voici une commande \xE0 arguments d\xE9limit\xE9s \verb-\bar-:
+\centrecode-\def\bar#1#2:#3\relax#4{<code>}-
+
+\begin{enumerate}
+	\item \Qu els sont les arguments d\xE9limit\xE9s ?
+	\item \Qu e valent les 4 arguments dans les cas suivants :
+\begin{enumerate}
+	\item \verb-\bar 123:456\relax789-
+	\item \verb-\bar\def\relax:\relax\relax\relax-
+	\item \verb-\bar:\relax:{\bar\relax}\bar\relax\bar-
+	\item \verb-\bar0:a\relax-
+\end{enumerate}
+\item Donner un cas o\xF9 l'on est s\xFBr d'obtenir une erreur de compilation.
+\item Donner un cas o\xF9 \verb-#1- vaut \xAB\verb-\bar12:34\relax5-\xBB et \verb-#3- vaut \xAB\verb-\relax-\xBB.
+\item Donner un cas o\xF9 \verb-#1- et \verb-#4- sont des arguments vides, mais pas \verb-#2- et \verb-#3-.
+\end{enumerate}
+
+\solution
+Rappelons la d\xE9finition de \verb-\bar- : \verb-\def\bar#1#2:#3\relax#4{<code>}-
+\begin{enumerate}
+	\item Les arguments d\xE9limit\xE9s sont le deuxi\xE8me et le troisi\xE8me. Il est important de noter que le 4\ieme{} n'est pas d\xE9limit\xE9.
+	\item Voici les r\xE9sultats pr\xE9sent\xE9s dans un tableau :
+		\begin{centrage}\small
+			\begin{tabular}[t]{lcccc}\hline
+				& \verb-#1- & \verb-#2- & \verb-#3- & \verb-#4-\\\hline
+				a) & \verb-1- &\verb-23-&\verb-456-&\verb-7-\\
+				b) &\verb-\def- &\verb-\relax- &<vide> &\verb-\relax-\\
+				c) &\verb-:-&\verb-\relax- &\verb-{\bar\relax}\bar- &\verb-\bar-\\
+				d) &\verb-0-&<vide>&\verb-a-&<inconnu>\\\hline
+			\end{tabular}
+		\end{centrage}
+		Les  chiffres 8 et 9 au premier exemple et le dernier \idx\relax au deuxi\xE8me exemple ne sont pas pris en compte par la macro \verb-\bar-.
+		
+		L'argument \verb-#4- de la derni\xE8re ligne est qualifi\xE9 d'\xABinconnu\xBB, car l'argument qui suit \xAB\verb-\bar0:a\relax-\xBB n'est pas pr\xE9cis\xE9 dans l'\xE9nonc\xE9. Si cet argument est \idx\par ou deux retours \xE0 la ligne cons\xE9cutifs (ce qui est la m\xEAme chose), il y aura une erreur de compilation puisque dans ce cas, l'argument \verb-#4- serait ce \idx\par ce qui est interdit puisque la macro \verb-\bar- n'est pas d\xE9clar\xE9e \idx\long.
+	\item Ce code \xAB\verb-\bar:a\relax bcd\par-\xBB provoquera une erreur de compilation, car l'argument \verb-#1- qui n'est pas d\xE9limit\xE9 va capturer le \xAB\verb-:-\xBB qui ne sera plus visible par la macro \verb-\bar-. Celle-ci va donc poursuivre sa lecture jusqu'\xE0 trouver un autre \xAB\verb-:-\xBB pour affecter \xE0 l'argument d\xE9limit\xE9 \verb-#2- ce qu'elle a emmagasin\xE9 jusque l\xE0. Ce faisant, elle va tomber sur le \verb-\par- et comme cette macro  \verb-\bar- n'a pas \xE9t\xE9 d\xE9finie \idx\long, \TeX{} va \xE9mettre une erreur de compilation.
+	\item Par exemple \xAB\verb-\bar{\bar12:34\relax5}X:{\relax}\relax Y-\xBB o\xF9 ici les arguments 2 et 4 sont \xAB\verb-X-\xBB et \xAB\verb-Y-\xBB.
+	\item Par exemple \xAB\verb-\bar{}X:Y\relax{}-\xBB o\xF9 les arguments 2 et 3 sont \xAB\verb-X-\xBB et \xAB\verb-Y-\xBB.
+\end{enumerate}
+\end{exercice}
+
+\begin{exercice}
+\Qu el sera l'affichage produit par le code suivant ?
+
+\centrecode-\def\bar/#1#2/{*#1*#2*}
+\bar////-
+
+\solution
+\TeX{} attend \xAB\verb-/-\xBB juste apr\xE8s \verb-\bar-. Ce caract\xE8re est donc absorb\xE9. L'argument \verb-#1- n'est pas d\xE9limit\xE9, il re\xE7oit donc le second \xAB\verb-/-\xBB. Comme \verb-#2- est un argument d\xE9limit\xE9, il sera vide puisque le second d\xE9limiteur arrive imm\xE9diatement apr\xE8s \verb-#1-. Il reste le dernier \xAB\verb-/-\xBB qui n'a pas \xE9t\xE9 lu avec la macro \verb-\bar- et ses arguments; il sera donc affich\xE9 tel quel juste apr\xE8s la fin du texte de remplacement de \verb-\bar-.
+
+On obtient donc : {\ttfamily\def\bar/#1#2/{*#1*#2*}\bar////}
+\end{exercice}
+
+\begin{exercice}
+Soit une macro \verb-\baz- d\xE9finie de cette fa\xE7on : \verb-\def\baz#1\relax{#1}-. Elle ressemble un peu \xE0 la commande \xA7\identity que nous avons d\xE9j\xE0 vue \xE0 la page~\pageref{identity} sauf qu'ici, l'argument \verb-#1- est \emph{d\xE9limit\xE9}.
+
+Lorsqu'elles sont ex\xE9cut\xE9es, expliquer s'il y a des diff\xE9rences entre ces diff\xE9rentes lignes de code et si oui, lesquelles :
+
+\centrecode-\baz\let\bar=A\let\bidule=B\relax
+\baz{\let\bar=A\let\bidule=B}\relax
+\baz{\let\bar=A}{\let\bidule=B}\relax-
+\solution
+Pour la premi\xE8re ligne, l'argument \verb-#1- est ce qui se trouve entre \verb-\baz- et \verb-\relax-, donc le texte de remplacement de ce code est \xAB\verb-\let\bar=A\let\bidule=B-\xBB. \TeX{} va donc d\xE9finir deux lettres implicites.
+
+\xC0 la deuxi\xE8me ligne, \TeX{} lit l'argument \xAB\verb-{\let\bar=A\let\bidule=B}-\xBB. Comme il est r\xE9duit \xE0 un texte entre accolades, ces accolades sont supprim\xE9es\idx*{argument!suppression d'accolades} et donc cette ligne de code est strictement \xE9quivalente \xE0 la premi\xE8re.
+
+Pour la troisi\xE8me, l'argument est \xAB\verb-{\let\bar=A}{\let\bidule=B}-\xBB qui n'est pas r\xE9duit \xE0 un texte entre accolades et ces accolades ne seront donc pas supprim\xE9es lors de la lecture de l'argument. \TeX{} va donc d\xE9finir des lettres implicites \xE0 l'int\xE9rieur de deux groupes. Ces d\xE9finitions seront perdues \xE0 la fin de chaque groupe, c'est-\xE0-dire imm\xE9diatement apr\xE8s avoir \xE9t\xE9 d\xE9finies. Cette troisi\xE8me ligne de code n'a donc aucun effet qui survit \xE0 la fermeture des deux groupes.
+\end{exercice}
+
+Le d\xE9limiteur du dernier argument peut \xE9galement \xEAtre une accolade ouvrante. Lorsque la macro sera ex\xE9cut\xE9e, cela signifiera que \TeX{} s'attendra \xE0 ce que cet argument s'\xE9tende jusqu'\xE0 la prochaine accolade ouvrante.
+
+\begin{regle}
+Pour sp\xE9cifier que le dernier argument \verb|<i>| d'une macro doit \xEAtre d\xE9limit\xE9 par une accolade ouvrante, il faut \xE9crire dans le \idx{texte de param\xE8tre}
+
+\centrecode-#<i>#{-
+
+L'accolade qui suit le \cidx\# sert de d\xE9limiteur et marque aussi le d\xE9but du texte de remplacement.
+
+Lorsque la macro sera ex\xE9cut\xE9e, l'argument \verb|#<i>| s'\xE9tendra jusqu'\xE0 la prochaine accolade ouvrante\idx*{argument!d\xE9limit\xE9!par accolade}.
+\end{regle}
+
+Voici une macro \verb-\baz- o\xF9 son 3\ieme{} argument est d\xE9limit\xE9 par une accolade ouvrante :
+
+\showcode/\def\baz#1#2#3#{"#1", puis "#2" et enfin "#3".}
+\baz{abc}def{gh}ij/
+
+D'apr\xE8s les r\xE8gles vues dans ce chapitre, \verb|#1| est \xAB\verb|abc|\xBB, \verb|#2| est \xAB\verb|d|\xBB et l'argument d\xE9limit\xE9 \verb-#3- est bien \xAB\verb-ef-\xBB. La suite du code, \xAB\verb-{gh}ij-\xBB, ne sera pas lu par la macro \verb-\baz-. C'est pourquoi l'affichage produit par ce code se trouve apr\xE8s le point qui marque la fin de texte de remplacement de la macro \verb|\baz|.
+\grandsaut
+
+Voici enfin deux macros \xE0 usage \xABg\xE9n\xE9raliste\xBB en programmation, toutes les deux \xE0 arguments d\xE9limit\xE9s. La premi\xE8re \xA7\firstto at nil lit tout ce qui se trouve jusqu'au prochain \xAB\idx\@nil\xBB et en prend le premier argument non d\xE9limit\xE9. La seconde, \xA7\remainto at nil prend ce qui reste. Elles\footnote{Ces deux commandes sont \texttt{\string\@car} et \texttt{\string\@cdr} du noyau \LaTeX.} ne sont \emph{pas} \xE0 confondre avec \xA7\firstoftwo et \xA7\secondoftwo qui elles, ne sont pas \xE0 arguments d\xE9limit\xE9s\label{firstto at nil}.
+
+On remarque que le caract\xE8re  \xAB\verb|@|\xBB\idx*{"@ (nom de macros priv\xE9es)} fait partie du nom de ces deux macros ainsi que de \idx\@nil, ce qui est normalement interdit. Pour que cela soit possible, il faut modifier le code de cat\xE9gorie de l'arobase qui est naturellement 12 pour le mettre \xE0 11, celui des lettres, afin qu'il puisse servir \xE0 constituer un nom de macro. En \TeX{}, on doit \xE9crire \xAB\texttt{\string\catcode`\string\@=11}\xBB pour que \verb|@| devienne une lettre puis \xAB\texttt{\string\catcode`\string\@=12}\xBB pour revenir au r\xE9gime de catcode de l'arobase par d\xE9faut. En \LaTeX{}, les macros \idx\makeatletter et \idx\makeatother effectuent ces actions.
+
+La zone de ces modifications sera limit\xE9e aux d\xE9finitions des macros de telle sorte qu'il ne sera plus possible de se r\xE9f\xE9rer \xE0 ces macros par la suite. L'int\xE9r\xEAt est qu'elles deviennent \xAB priv\xE9es \xBB, terme qu'il faut comprendre au sens de \xAB envers du d\xE9cor r\xE9serv\xE9 \xE0 un usage de programmation \xBB, ou encore \xAB \xE0 ne pas mettre entre toutes les mains \xBB. Ainsi, l'utilisateur final ne peut pas y acc\xE9der, sauf \xE9videmment s'il effectue la man\oe uvre de modification du catcode de \verb|@|\footnote{\LaTeX3 utilise le caract\xE8re \xAB\texttt{\string_}\xBB pour ses macros priv\xE9es.}.
+
+Voici les d\xE9finitions et quelques exemples d'utilisation de \xA7\firstto at nil et \xA7\remainto at nil :
+
+\showcode/\catcode`\@11
+\long\def\firstto at nil#1#2\@nil{#1}\xA4\xA7*\firstto at nil\xA4
+\long\def\remainto at nil#1#2\@nil{#2}\xA4\xA7*\remainto at nil\xA4
+a) \firstto at nil foobar\@nil   \qquad b) \remainto at nil foobar\@nil  \par\xA4\idx*\qquad\xA4
+c) \firstto at nil {foo}bar\@nil \qquad d) \remainto at nil {foo}bar\@nil\xA4\xA7*\firstto at nil\xA7*\remainto at nil\xA4/
+
+On voit souvent cette macro \idx\@nil dans le code de \LaTeX{} et on la verra aussi fr\xE9quemment dans les macros de ce livre. On peut se demander ce qu'elle fait vraiment et quelle est sa d\xE9finition. La r\xE9ponse est tr\xE8s simple : il est admis que \idx\@nil est une macro \emph{non d\xE9finie} (et doit le rester) dont le seul usage est de servir de d\xE9limiteur pour argument d\xE9limit\xE9. Ici, une pr\xE9cision s'impose : le fait qu'elle ne soit pas d\xE9finie \emph{n'implique pas} que, en tant que d\xE9limiteur, elle soit interchangeable avec une autre macro non d\xE9finie.
+
+\begin{regle}
+Lorsqu'un d\xE9limiteur d'argument est une \idx{s\xE9quence de contr\xF4le}, \TeX{} ne prend pas en compte la signification de cette \idx{s\xE9quence de contr\xF4le} : seuls les caract\xE8res qui composent son nom sont examin\xE9s.
+\end{regle}
+
+Si par exemple, on d\xE9finit une macro \verb|\foo| ainsi :
+
+\centrecode-\def\foo#1\truc{<code>}-
+
+\noindent alors par la suite, \TeX{} s'attendra \xE0 ce que \verb|\foo| soit suivie d'un code (qui deviendra l'argument \verb|#1|) dont la fin sera marqu\xE9e par \verb|\truc| (c'est-\xE0-dire le caract\xE8re d'\xE9chappement suivi des lettres \verb|t|, \verb|r|, \verb|u| et \verb|c|). M\xEAme si une autre macro \verb|\machin| est rendue \idx\let-\xE9gale \xE0 \verb|\truc|, cette macro \verb|\machin| ne sera pas comprise comme le d\xE9limiteur de la macro \verb|\foo|.
+
+\begin{exercice}
+Existe-t-il une diff\xE9rence de comportement entre ces deux lignes de code et si oui, laquelle :
+
+\centrecode-\firstoftwo{<code1>}{<code2>}\xA4\xA7*\firstoftwo\xA4
+\firstto at nil{<code1>}{<code2>}\@nil\xA4\xA7*\firstto at nil\xA4-
+
+\solution
+Il n'y a pas de diff\xE9rence de comportement. Ces deux lignes se comportent de fa\xE7on identique. Dans les deux cas, l'argument \verb-#1- n'est pas d\xE9limit\xE9 et va \xEAtre d\xE9pouill\xE9 de ses accolades\idx*{argument!suppression d'accolades}. Leur texte de remplacement est donc pour toutes les deux : \verb-<code1>-. De plus, elles ont toutes les deux lu et absorb\xE9 l'argument \verb-<code2>- qui disparait dans leur texte de remplacement.
+
+Cette \xE9quivalence serait \xE9galement valable entre ces 3 lignes qui toutes ex\xE9cutent \verb|<code2>|:
+
+\centrecode-\secondoftwo{<code1>}{<code2>}\xA4\xA7*\secondoftwo\xA4
+\remainto at nil{<code1>}{<code2>}\@nil\xA4\xA7*\remainto at nil\xA4
+\remainto at nil{<code1>}<code2>\@nil\xA4\xA7*\remainto at nil\xA4-
+\end{exercice}
+
+\section{Mise en pratique}
+Les arguments d\xE9limit\xE9s ne pr\xE9sentent pas de difficult\xE9 th\xE9orique sp\xE9ciale, aussi il est temps de les utiliser sur un exemple.
+
+\subsection{Afficher ce qui est \xE0 droite d'un motif}\label{rightof}
+Nous allons nous employer \xE0 programmer une macro\xA7\rightof[|(] dont la syntaxe est
+
+\centrecode-\rightof{<chaine>}{<motif>}-
+
+\noindent et qui affiche ce qui est \xE0 gauche du \verb|<motif>| dans la \verb|<chaine>|, \xE9tant entendu que si \verb|<motif>| ne figure pas dans la \verb|<chaine>|, rien ne doit \xEAtre affich\xE9.
+
+Du c\xF4t\xE9 de la m\xE9canique interne, cette macro se contentera de lire ses deux arguments, de d\xE9finir et d'appeler une macro \verb|\right at of|. Cette macro, \xE0 arguments d\xE9limit\xE9s, sera charg\xE9e d'effectuer le travail.
+
+L'int\xE9r\xEAt du \xAB\verb|@|\xBB dans \xAB\verb|\right at of| est de marquer la fronti\xE8re entre macro publique et macro priv\xE9e pour d\xE9limiter ce qui a une syntaxe clairement d\xE9finie et stable dans le temps pour les macros publiques de ce qui est de la cuisine interne pour les macros priv\xE9es. Ces derni\xE8res sont susceptibles d'\xEAtre modifi\xE9es, voire supprim\xE9es pourvu que la syntaxe et les fonctionnalit\xE9s de la macro publique soient conserv\xE9es.
+\grandsaut
+
+Voici comment doit \xEAtre d\xE9finie la macro \verb|\right at of|:
+
+\centrecode-\def\rightof#1<motif>#2\@nil{#2}-
+
+\noindent o\xF9 le d\xE9limiteur \verb|<motif>| est l'argument \verb|#2| de la macro principale.
+
+Voici donc le code de \verb|\rightof| o\xF9, conform\xE9ment \xE0 ce qui a \xE9t\xE9 dit, les tokens de param\xE8tre \verb|#| sont doubl\xE9s pour la macro \xABfille\xBB \verb|\right at of| :
+
+\showcode/\catcode`\@=11 % "@" devient une lettre
+\def\rightof#1#2{%\xA4\xA7*\rightof\xA4
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+	\right at of#1\@nil% appelle la macro auxiliaire o\xF9 #1 est la <chaine>
+}
+\catcode`\@=12 %"@" redevient un signe\xA4\idx*\catcode\xA4
+--\rightof{Programmation}{g}--\par\xA4\defline\aaa\xA4
+--\rightof{Programmation}{gram}--\par
+--\rightof{Programmation}{on}--/
+
+\subsection{Les cas probl\xE9matiques}
+La macro fonctionne bien\ldots{} En apparence seulement, car le cas o\xF9 \verb|<chaine>| ne contient pas le \verb|<motif>| n'a pas encore \xE9t\xE9 examin\xE9 :
+
+\errcode/\catcode`\@=11 % "@" devient une lettre
+\def\rightof#1#2{%
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+	\right at of#1\@nil% appelle la macro auxiliaire
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{Gram}/{! Paragraph ended before \string\right at of was complete. <to be read again>}
+
+\TeX{} explique qu'un \idx\par a \xE9t\xE9 rencontr\xE9 avant que l'argument ne soit enti\xE8rement lu, ce qui est interdit puisque la macro n'est pas d\xE9clar\xE9e \idx\long. Le texte de remplacement de \verb-\rightof{Programmation}{z}- (cas de la ligne \no\aaa) permet d'analyser ce qui se passe. Le texte de remplacement est \xE9crit ci-dessous (les doubles \verb-##- ont \xE9t\xE9 remplac\xE9s par des simples puisque nous \xE9crivons le texte de remplacement) :
+
+\centrecode-\def\right at of#1z#2\@nil{#2}
+\entre@ Programmation\@nil-
+
+\noindent La premi\xE8re ligne sp\xE9cifie donc que la macro \verb-\right at of- doit \xEAtre suivie de quelque chose (l'argument \verb-#1-) qui s'\xE9tend jusqu'\xE0 \xAB\verb|z|\xBB puis de quelque chose (l'argument \verb-#2-) qui s'\xE9tend jusqu'au \idx\@nil. Or, \xAB\verb|z|\xBB ne figure pas entre \verb|\right at of| et \idx\@nil puisque ce qui s'y trouve est l'argument \verb|#1| de la macro \verb|rightof|, c'est-\xE0-dire \xAB Programmation\xBB ! C'est pourquoi \TeX{} le cherche jusqu'\xE0 tomber sur le \idx\par qui stoppe cette vaine recherche puisque la macro n'est pas d\xE9clar\xE9e \idx\long.
+
+Tout serait bien plus facile si on disposait d'une macro qui teste si le \verb|<motif>| est contenu dans \verb|<chaine>| : dans l'affirmative, il suffirait d'appeler la macro \verb|\right at of| pr\xE9c\xE9demment d\xE9finie et sinon, ne rien faire ce qui revient \xE0 ne rien afficher. Une telle macro, capable de faire un test, sera \xE9crite plus tard (voir page~\pageref{ifin}). En attendant, il faut trouver une astuce pour se prot\xE9ger de cet inconv\xE9nient.
+
+En fait aucune erreur ne serait \xE9mise si, quelle que soit la \verb|<chaine>|, \verb|\right at of| voyait toujours le \verb|<motif>| avant le \idx\@nil. Afin qu'il en soit ainsi, on va d\xE9lib\xE9r\xE9ment \xE9crire ce \verb|<motif>| quelque part entre \verb|\right at of| et \idx\@nil lors de l'appel \xE0 la macro \verb|\right at of|. L'\xE9crire juste avant le \idx\@nil nous assure que rien ne sera renvoy\xE9 dans le cas o\xF9 \verb|<chaine>| ne contient pas \verb|<motif>| puisque dans ce cas, \verb|##2| est vide :
+
+\showcode/\catcode`\@=11 % "@" devient une lettre
+\def\rightof#1#2{%\xA4\xA7*\rightof\xA4
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire\xA4\defline\aaa\xA4
+	\right at of#1#2\@nil% appelle la macro auxiliaire avec le motif #2\xA4\defline\bbb\xA4
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{ti}--\par
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{Gram}--/
+
+L'inconv\xE9nient qui saute aux yeux est que le motif \verb|#2|, ajout\xE9 juste avant \idx\@nil, est dirig\xE9 vers l'affichage lorsque la \verb|<chaine>| contient le \verb|<motif>| ! Tout simplement parce que l'argument \verb|##2| de \verb|\right at of| qui est affich\xE9 est ce qui se trouve entre la \emph{premi\xE8re} occurrence du \verb|<motif>| et \idx\@nil.
+
+Pour mieux comprendre ce qui se joue en coulisses, examinons ce qui se passe lorsque l'appel \xAB\verb|\rightof{Programmation}{g}|\xBB est ex\xE9cut\xE9 :
+
+\begin{enumerate}
+	\item la macro \verb|\right at of| est d\xE9finie par : \verb|\def\right at if#1g#2\@nil{#2}| \xE0 la ligne \no\aaa;
+	\item \xE9crire \xAB\verb|\right at of Programmationg\@nil|\xBB donne ce qui se trouve entre la premi\xE8re occurrence de \xAB\verb|g|\xBB et \idx\@nil, c'est donc \xAB\verb|rammationg|\xBB qui est affich\xE9.
+\end{enumerate}
+
+Proc\xE9dons de m\xEAme avec l'appel \xAB\verb|\rightof{Programmation}{z}|\xBB, cas o\xF9 le \verb|<motif>| n'est pas contenu dans la \verb|<chaine>| :
+
+\begin{enumerate}
+	\item la macro \verb|\right at of| est d\xE9finie par : \verb|\def\right at if#1z#2\@nil{#2}|;
+	\item \xE9crire \xAB\verb|\right at of Programmationz\@nil|\xBB donne ce qui se trouve entre \xAB\verb|z|\xBB et \idx\@nil, c'est-\xE0-dire rien.
+\end{enumerate}
+
+Comment faire en sorte que le \verb|<motif>| rajout\xE9 juste avant le \idx\@nil ne soit pas affich\xE9 dans le cas o\xF9 \verb|<motif>| est contenu dans \verb|<chaine>| ? R\xE9ponse : en incluant dans l'argument \verb|##2| de \verb|\right at of| une autre macro \xE0 argument d\xE9limit\xE9e qui fera disparaitre ce qui est ind\xE9sirable. Cette macro \xE0 argument d\xE9limit\xE9 sera \xA7\gobto@@nil et absorbera tout ce qui se trouve entre elle et le prochain \verb|\@@nil| rencontr\xE9. On note ici qu'il ne s'agit pas de \idx[|etc]\@nil mais de \verb|\@@nil| afin que le d\xE9limiteur de cette macro lui soit sp\xE9cifique :
+
+\centrecode-\def\gobto@@nil#1\@@nil{}-
+
+On va donc ajouter un \verb|\@@nil| lors de l'appel \xE0 la macro \verb|\right at of| :
+
+\centrecode-\right at of#1#2\@@nil\@nil-
+
+\noindent Et il nous reste \xE0 correctement placer la macro \xA7\gobto@@nil. Pour que ce \verb|\@@nil| soit toujours appari\xE9 avec une macro \xA7\gobto@@nil, que \verb|<motif>| soit contenu dans \verb|chaine| ou pas, il faut mettre \xA7\gobto@@nil juste avant et juste apr\xE8s \verb|#2| :
+
+\showcode/\catcode`\@=11 % "@" devient une lettre
+\def\gobto@@nil#1\@@nil{}\xA4\xA7*\gobto@@nil\xA4
+\def\rightof#1#2{%
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+	\right at of#1\gobto@@nil#2\gobto@@nil\@@nil\@nil% appelle la macro auxiliaire\xA4\xA7*\gobto@@nil\xA4
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par\xA4\xA7*\rightof\xA4
+--\rightof{Programmation}{ti}--\par
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{Gram}--/
+
+Faisons fonctionner la macro \xA7\rightof dans le cas o\xF9 \verb|<motif>| est contenu dans \verb|<chaine>|. Comme pr\xE9c\xE9demment, examinons quels sont ses arguments lorsque l'on \xE9crit \xAB\verb|\rightof{Programmation}{g}|\xBB:
+
+\begin{enumerate}
+	\item l'appel \xE0 la macro \verb|\right at of| se fait ainsi :
+	
+	\centrecode-\right at of Programmation\gobto@@nil g\gobto@@nil\@@nil\@nil-\xA7*\gobto@@nil
+	\item son argument \verb|#2|, qui est entre le premier \xAB\verb|g|\xBB et \verb|\@nil| est :
+	
+	\centrecode-rammation\gobto@@nil g\gobto@@nil\@@nil-
+	\item l'affichage qui en r\xE9sulte est bien \xABrammation\xBB car la macro \xA7\gobto@@nil absorbe tout ce qui se trouve jusqu'au \verb|\@@nil|. \TeX{} ne tient aucun compte de ce qu'il absorbe. \Qu e la macro \xA7\gobto@@nil y figure ou pas n'y change rien : la macro \xE0 argument d\xE9limit\xE9 effectue \xAB b\xEAtement \xBB son travail sans analyser ce qui se trouve dans son argument.
+\end{enumerate}
+
+Voici maintenant le cas o\xF9 \verb|<motif>| n'est contenu dans \verb|<chaine>|, comme lorsqu'on \xE9crit \xAB\verb|\rightof{Programmation}{z}|\xBB :
+
+\begin{enumerate}
+	\item la macro \verb|\right at of| est appel\xE9e par
+	
+	\centrecode-\right at of Programmation\gobto@@nil z\gobto@@nil\@@nil\@nil-
+	\item l'argument \verb|#2| se trouve entre le \xAB\verb|z|\xBB et le \verb|\@nil| :
+	
+	\centrecode-\gobto@@nil\@@nil-
+	\item gr\xE2ce \xE0 la d\xE9finition de \xA7\gobto@@nil, ce code ne se traduit par aucun affichage.
+\end{enumerate}
+
+Impliquer ainsi plusieurs macros \xE0 arguments d\xE9limit\xE9s et faire en sorte que la suivante h\xE9rite de l'argument de la pr\xE9c\xE9dente pour le traiter \xE0 son tour est couramment utilis\xE9 en programmation et d\xE9montre, comme dans ce cas particulier, la puissance des arguments d\xE9limit\xE9s. En revanche, la gymnastique mentale requise pour  mettre en place un tel dispositif et correctement envisager tous les cas est loin d'\xEAtre naturelle et demande une certaine habitude\ldots{} Le plus difficile est d'analyser un code d\xE9j\xE0 \xE9crit, voire de comprendre un code que l'on avait \xE9crit soi-m\xEAme et oubli\xE9 entre temps. \Qu i peut se vanter de comprendre du premier coup d'\oe il l'appel \xE0 la macro auxiliaire mise au point pr\xE9c\xE9demment ?
+
+\centrecode-\right at of#1\gobto@@nil#2\gobto@@nil\@@nil\@nil-\xA7*\gobto@@nil
+
+Le manque de lisibilit\xE9 est criant et d\xE9montre l'importance de commenter son code, autant pour soi-m\xEAme que pour les autres. Pour augmenter la lisibilit\xE9 du code, il serait pr\xE9f\xE9rable de recourir \xE0 une macro \verb|\ifin| (dont l'\xE9laboration sera expliqu\xE9e page~\pageref{ifin}) qui teste si l'argument \verb|#1| contient l'argument \verb|#2| et ayant pour syntaxe
+
+\centrecode-\ifin{#1}{#2}
+	{<code \xE0 ex\xE9cuter si vrai>}
+	{<code \xE0 ex\xE9cuter si faux>}%-
+
+\noindent On peut ainsi programmer plus confortablement et utiliser la toute premi\xE8re version de \verb|\rightof| et se dispenser d'envisager le cas probl\xE9matique o\xF9 \verb|<chaine>| ne contient pas le \verb|<motif>| :
+
+\showcode/\catcode`\@=11 % "@" devient une lettre
+\xA4\string\def\string\if{}in\#1\#2\#3\#4\string{<\textit{code vu plus tard}\string}>\xA4
+\def\rightof#1#2{%\xA4\xA7*\rightof\xA4
+	\ifin{#1}{#2}%
+		{% si #1 contient le #2
+		\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+		\right at of#1\@nil% appelle la macro auxiliaire
+		}%
+		{}% sinon, ne rien faire
+}
+\catcode`\@=12 %"@" redevient un signe\xA4\idx*\catcode\xA4
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{o}--/
+
+\subsection{\xC0 gauche toute}\label{leftof}
+Ne nous arr\xEAtons pas en si bon chemin et venons-en \xE0 la macro sym\xE9trique de \xA7\rightof, la macro \xA7\leftof[|(] qui sera charg\xE9e d'afficher ce qui est \xE0 gauche du \verb|<motif>| dans la \verb|<chaine>|.
+
+Pour se pr\xE9munir de l'erreur de compilation rencontr\xE9e dans le cas o\xF9 le \verb|<motif>| (argument \verb|#2|) n'est pas contenu dans la \verb|<chaine>| (argument \verb|#1|), proc\xE9dons comme avec \xA7\rightof et ajoutons ce \verb|<motif>| lors de l'appel \xE0 la macro auxiliaire :
+
+\showcode/\catcode`\@=11
+\def\leftof#1#2{%\xA4\xA7*\leftof\xA4
+	\def\leftof at i##1#2##2\@nil{##1}% renvoie ce qui est \xE0 gauche de #2
+	\leftof at i #1#2\@nil% ajoute #2 apr\xE8s #1
+}
+\catcode`\@=12
+--\leftof{Programmation}{ram}--\par
+--\leftof{Programmation}{zut}--\xA4\xA7*\leftof\xA4/
+
+Cela \xE9tait attendu : lorsqu'on \xE9crit \verb|\leftof at i #1#2\@nil|, si \verb|#1| ne contient pas \verb|#2|, alors le \verb|#2| ajout\xE9 en fin d'argument devient la premi\xE8re occurrence du \verb|<motif>| et donc, \verb|#1| est affich\xE9 en entier.
+
+\xC0 nouveau, il va falloir d\xE9ployer une m\xE9thode astucieuse pour que, lorsque \verb|#1| est renvoy\xE9 en entier (ce qui correspond au cas probl\xE9matique), rien ne soit affich\xE9. Pour cela, la macro auxiliaire \verb|\leftof at i| ne va pas afficher, \verb|##1| mais transmettre ce \xAB\verb|##1#1|\xBB \xE0 une autre macro auxiliaire \verb|\leftof at ii|. Cette derni\xE8re aura comme d\xE9limiteur d'argument est \verb|#1| tout entier et se chargera d'afficher ce qui est \xE0 gauche de la \verb|<chaine>| \verb|#1| :
+
+\centrecode-\def\leftof at ii##1#1##2\@nil{##1}-
+
+Ainsi, la macro \verb|\leftof at i| devient :
+
+\centrecode-\leftof at i##1#2##2\@nil{\leftof at ii##1#1\@nil}-
+
+\noindent et on ajoute ici aussi \verb|#1| apr\xE8s \verb|##1| pour que la macro \verb|\leftof at ii| voie toujours la \verb|<chaine>| \verb|#1| :
+
+\showcode/\catcode`\@=11
+\def\leftof#1#2{%\xA4\xA7*\leftof\xA4
+	\def\leftof at i##1#2##2\@nil{\leftof at ii##1#1\@nil}%
+	\def\leftof at ii##1#1##2\@nil{##1}%
+	\leftof at i #1#2\@nil
+}
+\catcode`\@=12 \xA4\idx*\catcode\xA4
+--\leftof{Programmation}{ram}--\par
+--\leftof{Programmation}{zut}--/
+
+Compte tenu de la faible lisibilit\xE9 de ce code et de la difficult\xE9 \xE0 suivre comment se transmettent les arguments, voici un tableau montrant comment sont lus et isol\xE9s les arguments d\xE9limit\xE9s dans le cas o\xF9 \verb|<chaine>| contient \verb|<motif>|, c'est-\xE0-dire le premier cas. On a encadr\xE9 ce qui d\xE9limite les arguments des macros :
+
+\begin{centrage}
+	\footnotesize
+	\frboxsep=0.5pt
+	\def\mystrut{\vphantom{\normalfont Programmation}}
+	\begin{tabular}{|r|c|}\hline
+		Appel macro principale & \verb|\leftof{Programmation}{ram}|\\\hline
+		Appel \xE0 \verb|\leftof at i|& \frbox{\ttfamily\mystrut\string\leftof at i}Prog\frbox{\mystrut ram}mationram\verb|\@nil|\\
+		Argument \verb|##1| retenu par \verb|\leftof at i| & Prog\\\hline
+		Appel \xE0 \verb|\leftof at ii|& \frbox{\ttfamily\mystrut\string\leftof at ii}Prog\frbox{\mystrut Programmation}\verb|\@nil|\\
+		Argument \verb|##1| retenu par \verb|\leftof at ii| &\ttfamily Prog\\\hline
+		Affichage & Prog\\\hline
+	\end{tabular}
+\end{centrage}
+
+Voici maintenant le d\xE9roulement des op\xE9rations lorsque \verb|<chaine>| ne contient pas \verb|<motif>| :
+
+\begin{centrage}
+	\footnotesize
+	\frboxsep=0.5pt
+	\def\mystrut{\vphantom{\normalfont Programmation}}
+	\begin{tabular}{|r|c|}\hline
+		Appel macro principale & \verb|\leftof{Programmation}{zut}|\\\hline
+		Appel \xE0 \verb|\leftof at i|& \frbox{\ttfamily\mystrut\string\leftof at i}Programmation\frbox{\mystrut zut}\verb|\@nil|\\
+		Argument \verb|##1| retenu par \verb|\leftof at i| & Programmation\\\hline
+		Appel \xE0 \verb|\leftof at ii|& \frbox{\ttfamily\mystrut\string\leftof at ii}\kern.5pt \frbox{\mystrut Programmation}Programmation\verb|\@nil|\\
+		Argument \verb|##1| retenu par \verb|\leftof at ii| &\ttfamily <vide>\\\hline
+		Affichage & \ttfamily <vide>\\\hline
+	\end{tabular}
+\end{centrage}
+
+Il est bon de noter que la macro \xA7\leftof, bien que requ\xE9rant elle aussi deux macros auxiliaires, est programm\xE9 diff\xE9remment de \verb|\rightof|. Dans le cas de \xA7\leftof, la deuxi\xE8me macro auxiliaire \verb|\leftof at ii| est appel\xE9e \emph{dans l'argument} de \verb|\leftof at i|. Dans le cas de \verb|\rightof|, la deuxi\xE8me macro auxiliaire \xA7\gobto@@nil \xE9tait \xE9crite dans l'appel \xE0 la macro \verb|\right at of|, ce qui est un cas particulier pas toujours faisable.
+
+\begin{exercice}
+Modifier la macro \xA7\rightof pour utiliser la m\xE9thode employ\xE9e avec \xA7\leftof : la premi\xE8re macro auxiliaire \verb|\rightof at i| appellera \emph{dans son argument} une deuxi\xE8me macro auxiliaire \verb|\rightof at ii|.
+
+\solution
+On utilise une astuce similaire \xE0 celle vue avec \xA7\leftof : la deuxi\xE8me macro auxiliaire \verb|\rightof at ii| va renvoyer ce qui est \xE0 \emph{gauche} du \verb|<motif>| puisque celui-ci, ind\xE9sirable, \xE9tait rajout\xE9 \xE0 la toute fin de l'appel \xE0 \verb|\rightof at i| :
+
+\showcode/\catcode`\@=11
+\def\rightof#1#2{%\xA4\xA7*\rightof\xA4
+	\def\rightof at i##1#2##2\@nil{\rightof at ii##2#2\@nil}%
+	\def\rightof at ii##1#2##2\@nil{##1}%
+	\rightof at i#1#2\@nil
+}
+\catcode`\@=12 \xA4\idx*\catcode\xA4
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{z}--/
+
+Il est int\xE9ressant de noter que lorsque le \verb|<motif>| est \xAB\verb|z|\xBB, l'argument \verb|##2| de \verb|\rightof at i| est vide et donc, l'argument \verb|##1| de \verb|\rightof at ii| est vide aussi.
+\end{exercice}\xA7*\leftof[|)]
+
+\subsection{Autre probl\xE8me : les accolades dans le motif}\label{rightof.et.accolades}
+On n'en a pas fini avec les cas probl\xE9matiques\ldots{} Examinons maintenant pourquoi la macro \verb-\rightof- ne fonctionne pas lorsqu'elle est appel\xE9e avec un argument \verb|#2| contenant un (ou des) groupe(s) entre accolades. Voici un exemple simple o\xF9 une erreur de compilation est produite :
+
+\errcode/\catcode`\@=11
+\def\gobto@@nil#1\@@nil{}\xA4\xA7*\gobto@@nil\xA4
+\def\rightof#1#2{%
+	\def\right at of##1#2##2\@nil{##2}% d\xE9finit la macro auxiliaire
+	\right at of#1\gobto@@nil#2\gobto@@nil\@@nil\@nil% appelle la macro auxiliaire\xA4\xA7*\gobto@@nil\xA4
+}
+\catcode`\@=12
+\rightof{abc{1}def}{c{1}d}% affiche ce qui est \xE0 droite de "c{1}d"/{You can't use `macro parameter character \string##' in horizontal mode.}
+
+\noindent Pour comprendre ce qu'il se passe avec le token \xAB\verb-#-\xBB qui est incrimin\xE9 dans le message d'erreur, \xE9crivons le texte de remplacement de \verb|\rightof{abc{1}def}{c{1}d}| :
+
+\centrecode/\def\right at of##1c{1}d##2\@nil{##2}
+\right at of abc{1}def\gobto@@nil c{1}d\gobto@@nil\@@nil\@nil\xA4\xA7*\gobto@@nil\xA4/
+
+Le probl\xE8me se trouve \xE0 la premi\xE8re ligne. \TeX{} va lire \xAB\verb-\def\right at of##1c{1}-\xBB ce qui va d\xE9finir la macro auxiliaire \verb-\rightof at - : elle sera donc \xE0 argument d\xE9limit\xE9 par \xAB\verb|c|\xBB et son texte de remplacement sera \xAB\verb|1|\xBB. Par la suite, les tokens qui restent \xE0 lire sont \xAB\verb-d##2\@nil{##2}-\xBB. Ceux-ci n'\xE9tant plus dans le \idx{texte de param\xE8tre} d'une macro, \TeX{} bute \xAB\verb-#-\xBB, car ce token est justement attendu dans le texte de param\xE8tre d'une macro\footnote{On le rencontre aussi dans le pr\xE9ambule d'un alignement initi\xE9 par la primitive \texttt{\string\halign} ou \texttt{\string\valign}.}. Le message d'erreur signale donc que \TeX{} rencontre ce token dans un contexte (ici, le mode horizontal\idx*{mode!horizontal}) dans lequel il est interdit. D'ailleurs, si le mode en cours avait \xE9t\xE9 le mode vertical\idx*{mode!vertical}, le message aurait \xE9t\xE9 le m\xEAme : \xAB\texttt{You can't use `macro parameter character \#' in vertical mode.}\xBB
+
+Il est difficile de modifier la macro \xA7\rightof[|)] pour qu'elle puisse aussi trouver ce qui est entre deux arguments qui comportent des groupes entre accolades, car dans ces cas, les arguments d\xE9limit\xE9s sont interdits. Nous emploierons une tout autre m\xE9thode, bien plus lente, qui consisterait \xE0 s'y prendre token par token (voir page~\pageref{parser.code}).
+
+\begin{regle}
+Les d\xE9limiteurs figurant dans le \idx{texte de param\xE8tre} d'une macro ne peuvent pas contenir de tokens de catcode 1\idx*{catcode!1 (accolade)} ou 2 \xE9quilibr\xE9s (accolade ouvrante et fermante) car celles-ci seraient interpr\xE9t\xE9es non pas comme faisant partie d'un d\xE9limiteur, mais comme marquant les fronti\xE8res du texte de remplacement.\medskip
+
+La cons\xE9quence est donc que lorsqu'une macro d\xE9finit une \idx{macro fille} \xE0 argument d\xE9limit\xE9 o\xF9 les d\xE9limiteurs sont les arguments de la macro m\xE8re, ceux-ci ne peuvent pas contenir un groupe entre accolades.
+\end{regle}\idx*[|)]{argument!d\xE9limit\xE9}
+
+\chapter{D\xE9veloppement}\idx*[|(]{d\xE9veloppement}
+\TeX{} est un langage particulier et parmi d'autres subtilit\xE9s, le d\xE9veloppement est un de ses m\xE9canismes intimes. Maitriser le d\xE9veloppement est n\xE9cessaire pour programmer, car cette notion occupe une place centrale dans la programmation \TeX. Certains diraient que la gestion du d\xE9veloppement fait partie des choses assez p\xE9nibles, mais lorsqu'on programme, il est souvent n\xE9cessaire de savoir contr\xF4ler finement ce m\xE9canisme fondamental. Ce chapitre, consacr\xE9 \xE0 l'apprentissage des outils permettant de contr\xF4ler le d\xE9veloppement, nous ouvrira la voie pour appr\xE9hender la programmation abord\xE9e dans les parties suivantes.
+
+\section{D\xE9veloppement des commandes}
+Int\xE9ressons-nous aux commandes (qui ont un texte de remplacement donc), par opposition aux \idx{primitive}s qui sont \xAB cod\xE9es en dur \xBB dans \TeX{}. Le texte de remplacement est, en quelque sorte, la d\xE9finition de la commande, c'est-\xE0-dire la repr\xE9sentation interne qu'en a \TeX{}. Reprenons par exemple la commande tr\xE8s simple \verb-\foo- d\xE9finie par :
+
+\centrecode-\def\foo{Bonjour}-
+
+\noindent Son texte de remplacement est \xAB Bonjour \xBB, c'est-\xE0-dire que dans le code, lorsque \TeX{} va rencontrer \verb-\foo-, alors il va aller chercher sa signification dans sa m\xE9moire et va remplacer cette \idx{s\xE9quence de contr\xF4le} par son texte de remplacement qui est \xAB Bonjour \xBB. Ce remplacement, cette substitution, cette transformation du code s'appelle le \xAB d\xE9veloppement \xBB, et on dit que la macro \verb-\foo- a \xE9t\xE9 d\xE9velopp\xE9e par \TeX{}. Pour \xEAtre tout \xE0 fait clair, cette \xAB transformation du code \xBB, a lieu dans la m\xE9moire de \TeX{} (nomm\xE9e \xAB \idx{pile d'entr\xE9e} \xBB). Le code source n'est bien \xE9videmment pas modifi\xE9.
+
+\begin{regle}[R\xE8gle et d\xE9finition]
+\TeX{} est un langage de macros, c'est-\xE0-dire qu'il agit comme un outil qui \emph{remplace} du code par du code. Ce remplacement, aussi appel\xE9 d\xE9veloppement, a lieu dans une zone de m\xE9moire nomm\xE9e \og \idx{pile d'entr\xE9e}\fg.
+
+Ainsi, lorsque \TeX{} ex\xE9cute une macro, elle (ainsi que ses \xE9ventuels arguments) est d'abord remplac\xE9e par le code qui lui a \xE9t\xE9 donn\xE9 lorsqu'on l'a d\xE9finie avec \verb|\def|. Ce code est le \og \idx{texte de remplacement}\fg{}. Une fois que ce d\xE9veloppement a \xE9t\xE9 fait, \TeX{} continue sa route en tenant compte du remplacement effectu\xE9.
+\end{regle}
+
+Prenons le temps d'examiner en d\xE9tail ce qui se passe r\xE9ellement et d\xE9finissons les conventions suivantes : le symbole \TeXhead{} repr\xE9sente l'endroit o\xF9 \TeX{} s'appr\xEAte \xE0 lire la suite du code. On a vu qu'il ne lisait que ce dont il avait besoin, et on va donc encadrer en pointill\xE9s le ou les tokens que \TeX{} va lire \xE0 la prochaine \xE9tape. Lorsque le d\xE9veloppement se fait, la pile est encadr\xE9e. Observons donc, \xE9tape par \xE9tape ce qui se passe lorsqu'on \xE9crit \xAB\verb-\foo le monde-\xBB (l'espace apr\xE8s \verb-\foo- sera ignor\xE9 en vertu de la r\xE8gle concernant les espaces du code vue \xE0 la page~\pageref{regle.espace}) :\smallbreak
+
+\hspace{5em}\TeXhead\verb-\foo le monde-\par\nobreak
+\hspace{5em}\TeXhead{\ttfamily\fboxsep1pt \dashbox{\string\foo}le monde}\par\nobreak
+\hspace{5em}\TeXhead{\ttfamily\fboxsep1pt \fbox{ Bonjour}le monde}\smallbreak
+
+\noindent Ayant d\xE9velopp\xE9 la commande \verb-\foo- dans sa pile, \TeX{} continue \xE0 lire le code qu'il a obtenu. Ici, cela se solderait par la lecture des caract\xE8res \xABBonjourle monde\xBB et par leur affichage.
+
+Il est important de comprendre que la notion de d\xE9veloppement ne s'applique qu'\xE0 des s\xE9quences de contr\xF4le ou des caract\xE8res actifs. On peut donner la d\xE9finition suivante :
+
+\begin{regle}[D\xE9finition]Une \idx{s\xE9quence de contr\xF4le} est d\xE9veloppable si \TeX{} peut la remplacer par un code diff\xE9rent.\end{regle}
+
+Les primitives n'ont pas de \idx{texte de remplacement}. Cependant, certaines d'entre elles sont d\xE9veloppables. Nous en avons rencontr\xE9 une qui est la paire \idx\csname\linebreak[1]\verb-...-\linebreak[1]\idx\endcsname dont l'argument est le code qui se trouve entre elles. En effet, lorsque \TeX{} les ex\xE9cute, il transforme leur argument en une \idx{s\xE9quence de contr\xF4le}. Cette action recoupe la d\xE9finition donn\xE9e juste au-dessus : le code qui est substitu\xE9 est bien diff\xE9rent de ce qu'il y avait avant le d\xE9veloppement.
+
+La plupart des primitives ne sont pas d\xE9veloppables en ce sens que si l'on force leur d\xE9veloppement (nous verrons comment), on obtient la primitive elle-m\xEAme. L'action de ces primitives est de provoquer une action par le processeur lorsqu'elles sont ex\xE9cut\xE9es par \TeX{}. Par exemple, pour la primitive \verb|\def| qui n'est pas d\xE9veloppable, son action est de ranger dans la m\xE9moire de \TeX{} le texte de remplacement d'une macro. Les caract\xE8res de code de cat\xE9gorie 11 comme \xAB\verb-A-\xBB ou m\xEAme ceux dont le code de cat\xE9gorie est moins inoffensif comme \xAB\verb-$-\xBB ne sont pas d\xE9veloppables non plus. Comme les primitives non d\xE9veloppables, ils provoquent une action via le programme \texttt{tex} qui est de placer ce caract\xE8re dans la page pour les lettres et passer en mode math\xE9matique\idx*{mode!math\xE9matique} pour \verb-$-. Seuls les caract\xE8res rendus actifs dont le code de cat\xE9gorie est 13 peuvent se d\xE9velopper puisque leur comportement est similaire \xE0 celui des commandes.
+
+Prenons maintenant l'exemple suivant o\xF9 la macro \verb-\foo- admet 2 arguments :
+\centrecode-\def\foo#1#2{Bonjour #1 et #2}-
+
+\noindent Faisons l'hypoth\xE8se que l'on stocke deux pr\xE9noms \xABAlice\xBB et \xABBob\xBB dans les deux macros suivantes :
+\centrecode-\def\AA{Alice } \def\BB{Bob }-
+
+\noindent Pour bien comprendre le m\xE9canisme du d\xE9veloppement, prenons \xE0 nouveau le temps d'examiner en d\xE9tail ce qui va se passer lorsqu'on \xE9crit :
+
+\centrecode-\csname foo\ensdcsname\AA\BB et les autres-.
+
+\noindent Dans ce cas, voici les \xE9tapes par lesquelles \TeX{} va passer :
+\begingroup
+\fboxsep1pt
+\parskip1.5pt
+\def\beforecode{\ttfamily\hspace{5em}}
+\begin{enumerate}[parsep=0pt,itemsep=0pt]
+	\item lecture du code dont il a besoin pour former la commande \boxtoken\foo{} :\par
+		{\beforecode\TeXhead\dashbox{\string\csname\ foo\string\endcsname}\string\AA\string\BB\ et les autres.}
+	\item d\xE9veloppement de ce qui a \xE9t\xE9 lu, ce qui provoque la construction de la macro \verb-\foo- dans la pile :\par
+		{\beforecode\TeXhead\fbox{\string\foo}\string\AA\string\BB\ et les autres.}
+	\item la pile ne contenant pas les deux arguments requis pour la macro \verb-\foo-, ceux-ci sont donc lus \xE0 l'ext\xE9rieur de la pile :\par
+		{\beforecode\TeXhead\fbox{\rlap{\dashbox{\phantom{\string\foo\string\AA\string\BB}}}\string\foo}\string\AA\string\BB\ et les autres.}
+	\item d\xE9veloppement de \verb-\foo- et ses deux arguments qui provoque sa substitution par son texte de remplacement ;\par
+		{\beforecode\TeXhead\fbox{Bonjour \string\AA\ et \string\BB} et les autres.}
+	\item affichage de \xABBonjour\xBB et lecture du code jusqu'\xE0 \verb-\AA- :\par
+		{\beforecode Bonjour \TeXhead\fbox{\dashbox{\string\AA} et \string\BB} et les autres.}
+	\item d\xE9veloppement de \verb-\AA- :\par
+		{\beforecode Bonjour \TeXhead\fbox{Alice et \string\BB} et les autres.}
+	\item affichage de \xABAlice et \xBB et lecture du code jusqu'\xE0 \verb-\BB- ;\par
+		{\beforecode Bonjour Alice et \TeXhead\fbox{\dashbox{\string\BB}} et les autres.}
+	\item d\xE9veloppement de \verb-\BB- :\par
+		{\beforecode Bonjour Alice et \TeXhead\fbox{Bob} et les autres.}
+	\item lecture du code qui ne contient plus que des caract\xE8res inoffensifs jusqu'au \xAB\verb-.-\xBB :\par
+		{\beforecode Bonjour Alice et Bob et les autres.\TeXhead}
+\end{enumerate}
+\endgroup
+\grandsaut
+
+Il arrive qu'une \idx{s\xE9quence de contr\xF4le} puisse \xEAtre d\xE9velopp\xE9e plusieurs fois. Imaginons que l'on d\xE9finisse deux s\xE9quences de contr\xF4le \verb-\A- et \verb-\B- par ce code :
+
+\centrecode-\def\A{\B}
+\def\B{Salut}-
+
+Si l'on \xE9crit \verb-\A- dans le code, \TeX{} va proc\xE9der \xE0 son d\xE9veloppement et va la remplacer par \verb-\B-. Cette \idx{s\xE9quence de contr\xF4le} va \xEAtre d\xE9velopp\xE9e \xE0 son tour pour \xEAtre remplac\xE9e par \xAB Salut \xBB dans la pile. Dans ce cas, on dit que la macro \verb-\A- a \xE9t\xE9 2-d\xE9velopp\xE9e, c'est-\xE0-dire qu'elle a d\xFB subir 2 d\xE9veloppements successifs. On pourrait se repr\xE9senter la situation par des paquets cadeaux : la \idx{s\xE9quence de contr\xF4le} est le paquet cadeau (le contenant) et son d\xE9veloppement est le contenu. Pour les deux macros \verb-\A- et \verb-\B-, il s'agit d'un syst\xE8me de poup\xE9es gigognes o\xF9 le paquet cadeau \verb-\A- contient le paquet \verb-\B- qui lui-m\xEAme contient \xAB Salut \xBB. On comprend qu'il faut ouvrir 2 paquets pour prendre connaissance du contenu final :
+
+\begin{centrage}
+	\small\boxcs\A{\boxcs\B{Salut}}
+\end{centrage}
+
+Si au lieu de \verb-\A-, on avait \xE9crit \xAB\idx\csname\verb- A-\idx\endcsname\xBB, il aurait fallu ajouter un d\xE9veloppement de plus au d\xE9but pour transformer ce code en \verb-\A-. Et donc c'est apr\xE8s 3 d\xE9veloppements que \xAB\verb-\csname A\endcsname-\xBB donne \xABSalut\xBB.
+
+\begin{exercice}
+On d\xE9finit trois macros de cette fa\xE7on :
+
+\centrecode-\def\aa{\bb}
+\def\bb{\csname cc\endcsname}
+\def\cc{Bonjour}-
+
+Si on \xE9crit dans le code \idx\csname\verb- aa-\idx\endcsname, combien de d\xE9veloppements successifs \TeX{} doit-il effectuer pour que le code dans la pile soit \xABBonjour\xBB ?
+\solution
+Il suffit de compter les d\xE9veloppements. Dans le sch\xE9ma suivant, les fl\xE8ches signifient \xABse d\xE9veloppe en\ldots{}\xBB :
+
+\begin{center}
+\small
+\verb-\csname aa\endcsname- $\longrightarrow$ \verb-\aa- $\longrightarrow$ \verb-\bb- $\longrightarrow$ \verb|\csname cc\endcsname| $\longrightarrow$ \verb|\cc| $\longrightarrow$ Bonjour
+\end{center}
+
+Il faut donc 5 d\xE9veloppements.
+\end{exercice}
+
+\begin{exercice}
+On red\xE9finit les macros \verb-\aa- et \verb-\bb- de cette fa\xE7on :
+
+\centrecode-\def\aa{\bb}
+\def\bb{\def\cc{Bonjour}}-
+
+\Qu el est le 2-d\xE9veloppement de \verb-\aa-. Et le 3-d\xE9veloppement ?
+\solution
+Le 2-d\xE9veloppement de \verb-\aa- est \xAB\verb-\def\cc{Bonjour}-\xBB.
+
+Pour le 3-d\xE9veloppement, la question n'est pas claire. En effet, le 2-d\xE9veloppement que l'on voit \xE0 la ligne ci-dessus n'est pas un token unique est constitu\xE9 de 11 tokens. D'ailleurs, le seul qui est susceptible de se d\xE9velopper est \verb|\cc| puisque les autres sont soit une primitive (\verb|\def|), soit des accolades, soit des lettres. On va consid\xE9rer que le d\xE9veloppement ne s'applique qu'au premier token du code obtenu et la r\xE9ponse va donc \xEAtre : le 3-d\xE9veloppement est identique au 2-d\xE9veloppement, car la primitive \verb|\def| se d\xE9veloppe en elle-m\xEAme.
+\end{exercice}
+
+\begin{exercice}
+Red\xE9finissons les macros \verb-\aa-, \verb-\bb- et \verb|\cc| de cette fa\xE7on :
+
+\centrecode-\def\aa{X}
+\def\bb{Y}
+\def\cc{\secondoftwo\aa\bb 123}\xA4\xA7*\secondoftwo\xA4-
+
+\Qu el code est obtenu sur la pile apr\xE8s 1, 2 et 3 d\xE9veloppements de la macro \verb-\cc- ?
+\solution
+\xC9tat de la pile apr\xE8s :
+\begin{itemize}
+	\item 1 d\xE9veloppement : \verb-\secondoftwo\aa\bb 123-\xA7*\secondoftwo
+	\item 2 d\xE9veloppements : \verb-\bb 123-
+	\item 3 d\xE9veloppements : \verb-Y123-
+\end{itemize}
+\end{exercice}
+
+\noindent Les r\xE8gles suivantes d\xE9coulent de ce qui a \xE9t\xE9 dit :
+
+\begin{regle}[R\xE8gles]
+La lecture du code se fait s\xE9quentiellement de gauche \xE0 droite et \TeX{} ne cherche pas \xE0 lire plus de tokens que ce dont il a besoin.\medbreak
+
+Lorsque \TeX{} rencontre une s\xE9quence de contr\xF4le, il lit aussi ses \xE9ventuels arguments pour proc\xE9der \xE0 son d\xE9veloppement qui consiste \xE0 remplacer le tout par du code. Si la pile ne contient pas assez d'arguments, \TeX{} va chercher ces arguments manquants juste apr\xE8s la pile, c'est-\xE0-dire dans le code source.
+\end{regle}
+
+La premi\xE8re partie de cette r\xE8gle concernant la lecture s\xE9quentielle du code est extr\xEAmement contraignante et rend certaines choses impossibles. Par exemple d\xE9finir une \idx{s\xE9quence de contr\xF4le} form\xE9e avec \idx\csname et \idx\endcsname, comme la macro \texttt\textbackslash\boxtoken{ab1c}. En effet, comme on l'a vu \xE0 la page~\pageref{construction.nom.etrange}, c'est une erreur que d'\xE9crire :
+
+\centrecode-\def\csname ab1c\endcsname{<code>}-
+
+\noindent Nous avons vu \xE9galement \xE0 la page~\pageref{non.dev.csname} que l'on ne peut \xE9crire
+
+\centrecode-\let\salut\csname foo\endcsname-\idx*\let
+
+\noindent pour rendre la macro \verb|\salut| \xE9gale \xE0 \verb|\foo|.
+
+Concernant le d\xE9veloppement, \TeX{} permet d'enfreindre la premi\xE8re partie de la r\xE8gle en offrant la possibilit\xE9, dans une faible mesure, de d\xE9velopper le code \emph{non lin\xE9airement} et c'est ce que nous allons d\xE9couvrir avec la primitive \verb|\expandafter|.
+
+\section{La primitive \texttt{\textbackslash expandafter}}\idx*[|(]\expandafter
+Il n'est pas exag\xE9r\xE9 de dire qu'aux yeux de d\xE9butants en \TeX, \verb|\expandafter| est une des primitives les plus myst\xE9rieuses qui soient. Certains lui pr\xEAtent des vertus quasi magiques et en viendraient presque \xE0 croire que diss\xE9miner quelques \verb|\expandafter| dans un code qui ne fonctionne pas le ferait fonctionner ! Ici encore, il ne sera pas question de magie, mais au contraire de d\xE9mystification puisque cette  primitive \verb|\expanfafter| fait une chose extr\xEAmement simple.
+
+Tout d'abord, elle est d\xE9veloppable, c'est-\xE0-dire que lorsque \TeX{} va la d\xE9velopper, il va la remplacer par du code dans la pile. L'action de cette primitive se passe au niveau des tokens et non pas \xE0 celui des arguments. Si \verb|<x>| et \verb|<y>| sont deux tokens et si l'on \xE9crit :
+
+\centrecode-\expandafter<x><y>-
+
+\noindent cela a pour effet de 1-d\xE9velopper le token \verb-<y>- avant de lire \verb-<x>-. En fait, tout se passe comme si le \verb-\expandafter- permettait de \xABsauter\xBB \verb-<x>- pour 1-d\xE9velopper \verb-<y>- et revenir ensuite au point de d\xE9part.
+
+\begin{regle}
+Si \verb|<x>| et \verb|<y>| sont deux \emph{tokens}, \xE9crire
+
+\centrecode|\expandafter<x><y>|
+
+a pour effet, lorsque \TeX{} d\xE9veloppe \verb|\expandafter|, de 1-d\xE9velopper \verb|<y>| sans pour autant que la t\xEAte de lecture ne bouge de place (et donc reste devant \verb|<x>| qu'elle n'a toujours pas lu).
+
+Le \verb|\expandafter| disparait apr\xE8s s'\xEAtre d\xE9velopp\xE9 et on obtient donc
+
+\centrecode-<x><*y>-
+
+o\xF9 \xAB\verb|*|\xBB indique le 1-d\xE9veloppement du token \verb|<y>|.
+\end{regle}
+
+Attention, \verb|<y>| a \xE9t\xE9 1-d\xE9velopp\xE9, mais n'a pas \xE9t\xE9 \emph{lu}. La t\xEAte de lecture de \TeX{} n'a pas boug\xE9 dans l'op\xE9ration. On peut se repr\xE9senter la situation en imaginant que la t\xEAte de lecture dispose d'une \xAB t\xEAte de d\xE9veloppement \xBB, capable sur ordre de se d\xE9solidariser pour aller d\xE9velopper du code non encore lu. La t\xEAte de d\xE9veloppement, une fois sa mission accomplie, revient sur la t\xEAte de lecture afin que cette derni\xE8re poursuive son travail.
+
+Une application imm\xE9diate est que d\xE9sormais, nous pouvons d\xE9finir la \idx{s\xE9quence de contr\xF4le} \verb|\|\boxtoken{ab1c} avec \idx\csname : il suffit de sauter le \verb|\def| avec un \verb-\expandafter- pour provoquer la formation du nom de la macro avant que \verb-\def- ne la voit :
+
+\showcode/\expandafter\def\csname ab1c\endcsname{Bonjour}
+Texte de remplacement de la macro : \csname ab1c\endcsname/
+
+Au lieu d'\xE9crire \xAB\verb|\expandafter\def\csname ab1c\endcsname|\xBB, il est pr\xE9f\xE9rable de d\xE9finir une macro \xA7\defname dont l'argument est le nom de la macro. Il est facile de faire de m\xEAme avec \xA7\letname.
+
+\showcode/\def\defname#1{\expandafter\def\csname#1\endcsname}\xA4\xA7*\defname\idx*\csname\idx*\endcsname\xA4
+\defname{ab1c}{Bonjour}\xA4\xA7*\defname\xA4
+Texte de remplacement de \litterate|\abc1| : \csname ab1c\endcsname\par\xA4\xA7*\litterate\xA4
+\def\letname#1{\expandafter\let\csname#1\endcsname}\xA4\xA7*\letname\xA4
+\def\foo{abc}\letname{foo1}=\foo% rend la macro "\foo1" \xE9gale \xE0 \foo
+Texte de remplacement de \litterate|\foo1| : \csname foo1\endcsname\xA4\idx*\char\idx*\meaning\xA7*\litterate\xA4/
+
+Afin de comprendre l'utilit\xE9 du d\xE9veloppement, tentons maintenant une exp\xE9rience en utilisant la macro \xE0 arguments d\xE9limit\xE9s \xA7\firstto at nil[|(]. Nous l'avons d\xE9finie de la fa\xE7on suivante \xE0 la page~\pageref{firstto at nil} :
+
+\centrecode-\def\firstto at nil#1#2\@nil{#1}-
+
+\noindent son texte de remplacement est donc le premier argument de ce qui se trouve entre cette macro et \verb-\@nil-.
+
+Maintenant, si on d\xE9finit la macro \verb-\foo- par \verb|\def\foo{Bonjour}| et que l'on \xE9crit \verb|\firstto at nil\foo\@nil|, qu'obtient-on ?
+
+\showcode/ \def\foo{Bonjour}\catcode`@=11
+R\xE9sultat : \firstto at nil\foo\@nil\xA4\xA7*\firstto at nil\xA4
+\catcode`@=12/
+
+Contrairement \xE0 ce que l'on pourrait penser, on n'obtient pas la lettre \xABB\xBB mais le mot entier. C'est que, fort logiquement, \verb-\firstto at nil- a pris comme argument \verb-#1- la macro \verb-\foo- en entier tandis que l'argument d\xE9limit\xE9 \verb|#2| est rest\xE9 vide. Il \emph{essentiel} de ne pas confondre macro et texte de remplacement : dans un cas, il y a un seul token alors que dans l'autre, il y a tous les tokens du texte de remplacement, c'est-\xE0-dire ici les 7 lettres du mot \xABBonjour\xBB. Pour que \verb|\first at tonil| agisse sur le texte de remplacement de \verb|\foo| et non pas sur \verb|\foo| elle-m\xEAme, il faut d\xE9velopper \verb-\foo- \emph{avant} que \TeX{} ne lise la macro \verb-\firstto at nil-. Nous allons utiliser \verb-\expandafter- pour sauter \verb-\firstto at nil- et provoquer ce d\xE9veloppement :
+
+\showcode/\def\foo{Bonjour}\catcode`@=11 
+R\xE9sultat : \expandafter\firstto at nil\foo\@nil
+\catcode`@=12/
+
+\noindent Le m\xE9canisme est sch\xE9matis\xE9 ci-dessous :
+
+\begin{centrage}
+	\small\jumptok-\firstto at nil\foo-\verb-\@nil-
+\end{centrage}
+
+\noindent La fl\xE8che repr\xE9sente le d\xE9veloppement du token encadr\xE9. Ici donc, le d\xE9veloppement de \verb|\expandafter| va provoquer le 1-d\xE9veloppement de \verb|\foo| et donne :
+
+\centrecode-\firsto at nil Bonjour\@nil-
+
+\noindent Cette exp\xE9rience faite avec \verb|\firsto at nil| peut \xEAtre g\xE9n\xE9ralis\xE9e \xE0 n'importe quelle autre macro :
+
+\begin{regle}
+Lorsqu'on stocke des tokens dans une \verb|\<macroA>| (comme cela arrive tr\xE8s souvent), si l'on veut mettre ces tokens dans l'argument d'une autre macro \verb|\<macroB>|, il \emph{faut} d\xE9velopper \verb|\<macroA>| avant que \verb|\<macroB>| n'agisse.
+\end{regle}
+
+\begin{exercice}
+Au lieu d'une macro, utiliser un nouveau registre de token \verb|\testtoks| pour stocker les caract\xE8res \xAB Bonjour \xBB. Comment faut-il alors utiliser \xA7\firstto at nil pour obtenir la lettre \xAB B \xBB?
+\solution
+Pour extraire le contenu du registre, il faut d\xE9velopper la primitive \idx\the lorsqu'elle pr\xE9c\xE8de le registre. Ici, au lieu de 1-d\xE9velopper la macro, il faut 1-d\xE9velopper \idx\the\idx\toks0 :
+
+\showcode/\newtoks\testtoks \testtoks={Bonjour}\xA4\idx*\newtoks\xA4
+\catcode`@=11
+R\xE9sultat : \expandafter\firstto at nil\the\testtoks\@nil\xA4\idx*\the\xA4
+\catcode`@=12/
+\end{exercice}
+\grandsaut
+
+Afin de bien maitriser le d\xE9veloppement, abandonnons la macro \xA7\firstto at nil[|)]  pour construire une macro plus g\xE9n\xE9raliste \verb|\>| qui agit comme un r\xE9v\xE9lateur universel et qui affiche litt\xE9ralement tout ce qui se trouve entre \verb|\>| et \verb|<| :
+
+\centrecode|\>ensemble de tokens<|
+
+On voudrait que \verb|\>12^&$~\foo$<| affiche \xAB\detokenize{12^&$~\foo$}\xBB. Pour cela, la primitive \idx\detokenize va bien nous aider. Cette primitive d\xE9veloppable admet un argument entre accolades et le transforme en caract\xE8res de code de cat\xE9gorie 12 (et 10 pour l'espace). Par exemple, si on \xE9crit \verb-\detokenize{12^&$~\foo$}-,  on obtient \xAB \detokenize{12^&$~\foo$} \xBB.
+
+Il est utile de faire quelques remarques concernant \idx\detokenize : une espace est \emph{toujours} rajout\xE9e apr\xE8s une \idx{s\xE9quence de contr\xF4le}; ici, on peut la voir apr\xE8s \verb-\foo-. Enfin, l'argument doit contenir un texte o\xF9 les accolades sont \xE9quilibr\xE9es. Voici le code qui permet de programmer la macro \verb|\>| \xE9voqu\xE9e plus haut\label{macro.>} :
+
+\centrecode/\long\def\>#1<{\detokenize{#1}}/
+\long\def\>#1<{\detokenize{#1}}
+
+Exp\xE9rimentons cette macro et profitons de \verb-\expandafter- pour \xAB sauter \xBB la macro \verb-\>- afin de d\xE9velopper le premier token qui se trouve juste apr\xE8s :
+
+\showcode/\def\foo{bonjour}
+a) \>\csname foo\endcsname< \par\xA4\idx*\csname\idx*\endcsname\xA4
+b) \>\foo< \par
+c) \expandafter\>\foo< \par
+d) \>\foo\foo< \par
+e) \expandafter\>\foo\foo</
+
+Chaque fois qu'un \verb-\expandafter- pr\xE9c\xE8de \verb-\>- (cas c et e), on constate que le d\xE9veloppement du \verb-\foo- a bien lieu tout de suite apr\xE8s la balise. \xC0 la derni\xE8re ligne, on voit que le premier \verb-\foo- est d\xE9velopp\xE9 alors que le second, non concern\xE9 par le \verb-\expandafter- reste tel quel.
+
+Maintenant, essayons de 1-d\xE9velopper le \emph{second} \verb-\foo- de la derni\xE8re ligne tout en laissant le premier intact. Le principe est que le d\xE9veloppement d'un premier \verb|\expandafter| provoque le d\xE9veloppement d'un autre situ\xE9 un token apr\xE8s, et ainsi de suite pour finir par 1-d\xE9velopper le token voulu. Cette capacit\xE9 que poss\xE8dent les \verb|\expandafter| \xE0 se transmettre de proche en proche le d\xE9veloppement conduit \xE0 appeler ce genre de structure un \xAB pont d'\verb|\expandafter|\xBB :
+
+\begin{centrage}
+	\small\jumptok-\>\foo\foo-\verb-<-
+\end{centrage}
+
+Une fois que les \verb-\expandafter- se sont pass\xE9 le relai pour d\xE9velopper le second \verb-\foo-, ceux-ci disparaissent, et le code qui est pr\xEAt \xE0 \xEAtre lu est :
+
+\centrecode-\>\foo Bonjour<-
+
+\noindent ce que l'on v\xE9rifie dans cet exemple :
+
+\showcode/\def\foo{Bonjour} \expandafter\>\expandafter\foo\foo</
+
+La r\xE8gle fondamentale est la suivante :
+
+\begin{regle}
+Pour 1-d\xE9velopper un token pr\xE9c\xE9d\xE9 de $n$ tokens, il faut mettre un \verb-\expandafter- devant chacun de ces $n$ tokens.
+\end{regle}
+
+Par exemple, en partant de \verb-\foo-, si l'on veut d\xE9finir une macro \verb-\bar- dont le texte de remplacement soit \xAB\verb-\foo Bonjour-\xBB, alors on doit mettre un \verb-\expandafter-, repr\xE9sent\xE9 par un \xAB $\bullet$ \xBB devant les 4 tokens \boxtoken{\def}, \boxtoken{\bar}, \boxtoken[]{\{} et \boxtoken{\foo} pour provoquer le 1-d\xE9veloppement du second \verb-\foo- :
+
+\begin{centrage}
+	\small\ttfamily$\bullet$\string\def$\bullet$\string\bar$\bullet$\string{$\bullet$\string\foo\string\foo\string}
+\end{centrage}
+
+\showcode|\def\foo{Bonjour}
+\expandafter\def\expandafter\bar\expandafter{\expandafter\foo\foo}
+\meaning\bar|
+
+Une application de ceci, tr\xE8s utile en programmation, est l'ajout d'un \verb|<code>| au texte de remplacement d'une macro. Appelons \xA7\addtomacro[|(]\label{addtomacro} la commande qui admet deux arguments dont le premier est une macro et le second est un texte qui sera ajout\xE9 \xE0 la fin du texte de remplacement de la macro. On doit pouvoir \xE9crire :
+
+\centrecode-\def\foo{Bonjour}
+\addtomacro\foo{ le monde}-\xA7*\addtomacro
+
+\noindent pour qu'ensuite, la macro \verb-\foo- ait comme texte de remplacement \xAB Bonjour le monde \xBB. La m\xE9thode consiste \xE0 partir de cette d\xE9finition :
+
+\centrecode-\long\def\addtomacro#1#2{\def#1{#1#2}}-
+
+\noindent Si on \xE9crit \xAB\xA7\addtomacro\verb-\foo{ le monde}-\xBB, le texte de remplacement devient
+
+\centrecode-\def\foo{\foo Bonjour}-
+
+\noindent On le voit, le texte de remplacement va conduire \xE0 une d\xE9finition \emph{r\xE9cursive} de \verb-\foo- puisque le texte de remplacement de \verb|\foo| contient \verb|\foo|. Ouvrons une parenth\xE8se et int\xE9ressons-nous \xE0 ce qui va se passer.
+\grandsaut
+
+L'ex\xE9cution de \verb|\foo| telle que d\xE9finie ci-dessus va conduire \xE0 une erreur de compilation. En effet, \xE0 chaque d\xE9veloppement, non seulement \verb|\foo| est cr\xE9\xE9e dans la pile, mais 7 tokens (les 7 lettres du mot \xAB Bonjour \xBB) y sont aussi ajout\xE9s. La pile va donc croitre tr\xE8s rapidement, voici son contenu lors des premiers d\xE9veloppements :
+\begin{enumerate}
+	\item \verb|\foo|
+	\item \verb|\foo Bonjour|
+	\item \verb|\foo BonjourBonjour|
+	\item \verb|\foo BonjourBonjourBonjour|
+	\item etc.
+\end{enumerate}
+
+Cette pile n'\xE9tant pas infinie, le maximum va \xEAtre rapidement atteint :
+
+\errcode/\def\foo{\foo Bonjour}% d\xE9finition r\xE9cursive
+\foo% l'ex\xE9cution provoque un d\xE9passement de la capacit\xE9 de la pile/%
+{! TeX capacity exceeded, sorry [input stack size=5000].}
+
+Augmenter cette taille ne changerait pas l'issue, m\xEAme si des d\xE9veloppements suppl\xE9mentaires \xE9taient faits.
+\grandsaut
+
+Fermons la parenth\xE8se et revenons \xE0 \verb|\def\foo{\foo Bonjour}|. Afin d'\xE9viter l'\xE9cueil du d\xE9passement de la capacit\xE9 de la pile, il faut 1-d\xE9velopper \verb-\foo- \xE0 l'int\xE9rieur des accolades pour qu'elle soit remplac\xE9e par \xABBonjour\xBB et ce, \emph{avant} que \verb|\def| n'entre en action. Comme nous l'avons vu, il suffit de placer un \verb-\expandafter- devant chaque token qui pr\xE9c\xE8de ce \verb-\foo-. Voici le code correct qui permet de programmer la macro \verb-\addtomacro- :
+
+\showcode|\long\def\addtomacro#1#2{%\xA4\xA7*\addtomacro\xA4
+	\expandafter\def\expandafter#1\expandafter{#1#2}%
+}
+\def\foo{Bonjour}
+\addtomacro\foo{ le monde}\xA4\xA7*\addtomacro\xA4
+\meaning\foo\xA4\idx*\meaning\xA4|
+
+\begin{exercice}
+En utilisant \xA7\addtomacro, \xE9crire une macro \xA7\eaddtomacro qui agit comme \xA7\addtomacro sauf que le second argument est 1-d\xE9velopp\xE9. Ainsi, si on \xE9crit
+
+\centrecode-\def\foo{Bonjour} \def\world{ le monde}
+\eaddtomacro\foo\world-
+
+alors, le texte de remplacement de la macro \verb-\foo- doit \xEAtre \xABBonjour le monde\xBB.
+\solution
+Si nous partons de ceci :
+
+\centrecode-\long\def\eaddtomacro#1#2{\addtomacro#1{#2}}-
+
+le texte de remplacement est de \xA7\eaddtomacro est
+
+\centrecode-\addtomacro#1{#2}-
+
+Pour que \xA7\addtomacro acc\xE8de au texte de remplacement de la macro \verb|#2|, nous savons qu'\xE0 l'int\xE9rieur des accolades, \verb-#2- doit \xEAtre 1-d\xE9velopp\xE9e. Pour ce faire, il faut placer un \verb-\expandafter- devant chacun des 3 tokens qui pr\xE9c\xE8dent \verb-#2- :
+
+\showcode|\long\def\eaddtomacro#1#2{%\xA4\xA7*\eaddtomacro\xA4
+	\expandafter\addtomacro\expandafter#1\expandafter{#2}%
+}
+\def\foo{Bonjour} \def\world{ le monde}
+\eaddtomacro\foo\world\xA4\xA7*\eaddtomacro\xA4
+\meaning\foo\xA4\idx*\meaning\xA4|
+\end{exercice}\xA7*\addtomacro[|)]
+\grandsaut
+
+Nous allons maintenant construire les m\xEAmes macros sauf qu'elles agiront sur le contenu de registres de tokens. Mais pour atteindre ce but, une r\xE8gle va nous \xEAtre utile\ldots{}
+
+\begin{regle}\relax\label{primitive.suivie.par.accolade}
+Les primitives qui doivent imm\xE9diatement \xEAtre suivies d'une accolade ouvrante ont la particularit\xE9 suivante : elles d\xE9veloppent au maximum\idx*{d\xE9veloppement maximal} jusqu'\xE0 trouver l'accolade ouvrante.
+
+Nous connaissons :
+\begin{itemize}
+	\item \idx\lowercase et \idx\uppercase;
+	\item \idx\detokenize;
+	\item \idx\toks\verb*-<nombre>= - (ou \verb*-\<nom>= - si on est pass\xE9 par \idx\newtoks\verb-\<nom>-), sachant que le signe \verb|=| et l'espace qui le suit sont facultatifs.
+\end{itemize}
+
+La cons\xE9quence est que l'on peut placer un (ou plusieurs) \verb|\expandafter| entre ces primitives et l'accolade ouvrante pour d\xE9velopper leur argument avant qu'elles n'agissent.
+\end{regle}
+
+La m\xE9thode va consister \xE0 tirer parti de cette r\xE8gle. Si \verb|#1| est un registre de tokens, on va partir de
+
+\centrecode-#1= {\the#1#2}-
+
+\noindent et placer un \verb|\expandafter| entre \verb*|#1= | et l'accolade ouvrante pour 1-d\xE9velopper \verb|\the#1| afin de d\xE9livrer le contenu du registre \verb|#1| :
+
+\showcode/\long\def\addtotoks#1#2{#1= \expandafter{\the#1#2}}\xA4\xA7*\addtotoks\idx*\long\xA4
+\newtoks\bar\xA4\idx*\newtoks\xA4
+\bar={Bonjour}% met "Bonjour" dans le registre
+\addtotoks\bar{ le monde}% ajoute " le monde"\xA4\xA7*\addtotoks\xA4
+\the\bar% affiche le registre\xA4\idx*\the\xA4/
+
+En copiant la m\xE9thode utilis\xE9e avec \xA7\eaddtomacro, il est facile de construire la macro \xA7\eaddtotoks qui 1-d\xE9veloppe son second argument avant de l'ajouter au contenu du registre \xE0 token \verb|#1| :
+
+\showcode/\long\def\eaddtotoks#1#2{\expandafter\addtotoks\expandafter#1\expandafter{#2}}\xA4\xA7*\eaddtotoks\xA7*\addtotoks\xA4
+\bar={Bonjour}
+\def\macrofoo{ le monde}
+\eaddtotoks\bar\macrofoo\xA4\xA7*\eaddtotoks\xA4
+\the\bar\xA4\idx*\the\xA4/
+
+\section{D\xE9velopper encore plus avec \texttt{\textbackslash expandafter}}
+Jusqu'\xE0 pr\xE9sent, nous nous sommes limit\xE9s \xE0 des \verb|\expandafter| provoquant des 1-d\xE9veloppements, mais on peut 2-d\xE9velopper, voire plus. Pour voir comment, d\xE9finissons les macros
+
+\centrecode-\def\X{Bonjour} \def\Y{\X}-
+
+\noindent et int\xE9ressons-nous au probl\xE8me suivant : essayons de 2-d\xE9velopper le \xAB\verb-\Y-\xBB qui se trouve entre \verb-\>- et \verb-<- dans \xAB\verb-\>\Y<-\xBB de fa\xE7on \xE0 obtenir l'affichage \xABBonjour\xBB.
+
+Ce que nous savons faire, c'est 1-d\xE9velopper \verb-\Y- :
+
+\centrecode-\expandafter\>\Y<-
+
+\noindent En l'\xE9tat, ce code ne fait que 1-d\xE9velopper \verb|\Y|. Pour 2-d\xE9velopper, il faudrait que le \verb|\expandafter| ci-dessus agisse sur le 1-d\xE9veloppement de \verb|\Y|. On va donc partir du code ci-dessus et faire en sorte que pr\xE9alablement, le \verb|\Y| soit 1-d\xE9velopp\xE9. Nous savons comment placer les \verb-\expandafter- pour que la macro \verb-\Y- soit 1-d\xE9velopp\xE9e, il suffit d'en mettre un devant chaque token qui pr\xE9c\xE8de \verb-\Y-. Il faut donc placer un \verb-\expandafter- devant le premier \verb-\expandafter- et un autre devant \verb-\>-. On arrive au code suivant :
+
+\centrecode-\expandafter\expandafter\expandafter\>\Y<-
+
+\noindent Pour nous assurer que ce code va conduire au r\xE9sultat escompt\xE9, examinons ce qui se passe avec les conventions graphiques vues auparavant. Voici ce qui se passe dans un premier temps :
+
+\begin{centrage}
+	\small\jumptok-\expandafter\>\Y-\verb-<-
+\end{centrage}
+
+\noindent La macro \verb-\Y- est d\xE9velopp\xE9e en \verb-\X- et on obtient le code \xAB \verb-\expandafter\>\X<- \xBB dans la pile. Voici maintenant le deuxi\xE8me temps :
+
+\begin{centrage}
+	\small\jumptok-\>\X-\verb-<-
+\end{centrage}
+
+\noindent \verb-\X- se d\xE9veloppe bien en \xABBonjour\xBB ce qui donne :
+
+\centrecode-\>Bonjour<-
+
+\noindent que nous cherchions \xE0 obtenir. V\xE9rifions-le sur cet exemple :
+
+\showcode/\def\X{Bonjour} \def\Y{\X}
+\expandafter\expandafter\expandafter\>\Y</
+
+Ce pont d'\verb|\expandatfer| a provoqu\xE9 \emph{deux} d\xE9veloppements pour arriver au code final et on peut parler de \xAB pont \xE0 plusieurs niveaux \xBB.
+\grandsaut
+
+Retenons que lorsque deux tokens \verb-<x><y>- sont dans le code, pour 2-d\xE9velopper \verb-<y>- avant de lire \verb-<x>-, nous devons placer trois \verb-\expandafter- devant \verb-<x>- de cette fa\xE7on :
+\centrecode-\expandafter\expandafter\expandafter<x><y>-
+
+Et si nous voulions 3-d\xE9velopper \verb-<y>-, il faudrait ajouter des \verb|\expandafter| dans le code ci-dessus pour, au pr\xE9alable, 1-d\xE9velopper \verb-<y>-. Pour cela, il faudrait placer un \verb-\expandafter- devant chaque token qui pr\xE9c\xE8de \verb-<y>- et donc en ajouter 4 (un devant chacun des 3 \verb-\expandafter- existants et un devant \verb-<x>-). Nous aurions alors 7 \verb|\expandafter| en tout :
+
+\centrecode-\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter<x><y>-
+
+Pour un d\xE9veloppement de plus de \verb-<y>- de fa\xE7on \xE0 le 4-d\xE9velopper, il faudrait 1-d\xE9velopper \verb|<y>| dans le code ci-dessus et donc, ajouter 8 \verb|\expandatfer| de plus (un devant les 7 \verb-\expandafter- existants plus un devant \verb-<x>-) ce qui en ferait 15.
+\grandsaut
+
+Essayons d'en tirer une r\xE8gle g\xE9n\xE9rale : soit $u_k$ le nombre d'\verb-\expandafter- plac\xE9s devant les tokens \verb-<x><y>- qui provoquent le $k$-d\xE9veloppement de \verb|<y>|. Si on veut proc\xE9der \xE0 un d\xE9veloppement de plus de \verb-<y>-, il faut ajouter $u_k+1$ \verb-\expandafter- devant \verb-<x><y>- (un devant chacun des $u_k$ \verb-\expandafter- existants et un devant \verb-<x><y>-). Pour traduire ceci par une relation de r\xE9currence math\xE9matique, il suffit de partir de $u_1=1$ puisque un \verb|\expandafter|
+ plac\xE9 devant \verb|<x><y>| provoque le 1-d\xE9veloppement de \verb|<y>|. On a donc :
+
+\begin{align*}
+u_1&=1&u_{k+1}&=u_k+u_k+1\\
+&&&=2u_k+1
+\end{align*}
+
+\noindent \xC0 l'aide d'une d\xE9monstration math\xE9matique facile, on en tirerait que : 
+\[u_k=2^k-1\]
+
+Le raisonnement pourrait facilement \xEAtre g\xE9n\xE9ralis\xE9 si plusieurs tokens pr\xE9c\xE9daient \verb-<y>-. La r\xE8gle g\xE9n\xE9rale est la suivante et il est bon de s'en souvenir :
+
+\begin{regle}
+Pour provoquer le $k$-d\xE9veloppement d'un token \verb|<y>| pr\xE9c\xE9d\xE9 par $n$ autres tokens, il faut placer $2^k-1$ \verb-\expandafter- devant chacun des $n$ tokens qui le pr\xE9c\xE8dent.
+\end{regle}
+
+\begin{exercice}
+Reprenons les macros suivantes :
+
+\centrecode-\def\X{Bonjour}
+\def\Y{\X}-
+
+Placer les \verb-\expandafter- dans le code ci-dessous pour que le texte de remplacement de la macro \verb-\foo- soit \xAB Bonjour \xBB :
+
+\centrecode-\def\foo{\Y}-
+
+\solution
+La r\xE9ponse se trouve dans la r\xE8gle pr\xE9c\xE9dente : il faut 2-d\xE9velopper \verb-\Y- et donc ajouter $2^2-1$, c'est-\xE0-dire 3 \verb-\expandafter- devant chaque token qui pr\xE9c\xE8de \verb-\Y-. Ces tokens sont au nombre de 3 (\xAB\verb|\def|\xBB, \xAB\verb|\foo|\xBB et \xAB\verb|{|\xBB) et donc, il faut remplacer chaque \xAB $\bullet$ \xBB par 3 \verb-\expandafter- dans ce code :
+
+\begin{centrage}
+	\small$\bullet$\verb-\def-$\bullet$\verb-\foo-$\bullet$\verb-{\Y}-
+\end{centrage}
+
+\noindent Cela donne un code un peu indigeste :
+
+\centrecode-\expandafter\expandafter\expandafter\def
+\expandafter\expandafter\expandafter\foo
+\expandafter\expandafter\expandafter{\Y}-
+\end{exercice}
+
+\begin{exercice}
+Placer correctement des \verb-\expandafter- dans la derni\xE8re ligne du code ci-dessous pour que \verb-\bar- ait comme texte de remplacement \xAB Bonjour le monde \xBB :
+
+\centrecode-\def\foo{Bonjour}
+\def\world{ le monde}
+\def\bar{\foo\world}-
+\solution
+Si on part de
+
+\centrecode-\def\bar{\foo\world}-
+
+il faut 1-d\xE9velopper \verb|\foo| et 1-d\xE9velopper \verb|\world| dans le texte de remplacement de \verb|\bar|.
+
+Nous allons construire un pont d'\verb|\expandafter| en deux passes : la premi\xE8re 1-d\xE9veloppera une des deux macros et la deuxi\xE8me 1-d\xE9veloppera l'autre.
+
+Dans un cas comme celui-ci qui est un cas particulier d'un cas plus g\xE9n\xE9ral, il faut commencer par placer des \verb|\expandafter| pour 1-d\xE9velopper la macro la plus \xE0 gauche. Ceci \xE9tant fait, la passe suivante consistera \xE0 placer des \verb|\expandatfer| pour d\xE9velopper la macro suivante. Et ainsi de suite pour finir, lors de la derni\xE8re passe, par le d\xE9veloppement de la macro la plus \xE0 droite. On progresse donc de gauche \xE0 droite, c'est-\xE0-dire dans l'ordre inverse de celui dans lequel elles seront d\xE9velopp\xE9es par \TeX{} lorsqu'il lira le code.
+
+Ici donc, la premi\xE8re passe consiste \xE0 placer des \verb|\expandafter| pour 1-d\xE9velopper \verb|\foo|, ce qui revient \xE0 en placer un devant chaque token qui pr\xE9c\xE8de \verb|\foo| :
+
+\centrecode-\expandafter\def\expandafter\foo\expandafter{\foo\world}-
+
+Dans une deuxi\xE8me passe, nous allons 1-d\xE9velopper \verb-\world- et placer aussi un \verb-\expandafter- devant chaque token qui la pr\xE9c\xE8de, en tenant compte de ceux d\xE9j\xE0 mis en place :
+
+\centrecode-\expandafter\expandafter\expandafter\def
+\expandafter\expandafter\expandafter\foo
+\expandafter\expandafter\expandafter
+{\expandafter\foo\world}-
+
+Bien que ne r\xE9pondant pas aux contraintes de l'\xE9nonc\xE9, la macro \xA7\eaddtomacro peut se r\xE9v\xE9ler utile dans un cas comme celui-ci. En effet, elle am\xE9liore la lisibilit\xE9 du code puisqu'elle \xE9vite ces nombreux \verb|\expandafter|. Une autre fa\xE7on de faire aurait \xE9t\xE9 :
+
+\centrecode-\def\bar{}%
+\eaddtomacro\bar\foo
+\eaddtomacro\bar\world\xA4\xA7*\eaddtomacro\xA4-
+\end{exercice}
+
+La primitive \verb|\expandafter| intervenant au niveau des \emph{tokens}, il est int\xE9ressant en programmation de disposer d'une macro, appelons-la \xA7\expsecond[|(], qui intervient au niveau des \emph{arguments}. On voudrait qu'elle soit capable de sauter un argument entier pour 1-d\xE9velopper le premier token de l'argument qui suit. On pourrait donc \xE9crire :
+
+\centrecode-\expsecond{<arg1>}{<arg2>}-
+
+\noindent pour que le code finalement lu par \TeX{} soit
+
+\centrecode-<arg1>{*<arg2>}-
+
+\noindent o\xF9 l'\xE9toile indique que le premier token de \verb|<arg2>| est 1-d\xE9velopp\xE9. 
+
+\begin{exercice}\label{expsecond}
+Construire la macro \xA7\expsecond en utilisant la macro auxiliaire \xA7\swaparg[|(] qui \xE9change 2 arguments en mettant le premier entre accolades :
+
+\centrecode-\long\def\swaparg#1#2{#2{#1}}-
+
+\solution
+La m\xE9thode consiste \xE0 partir de
+
+\centrecode-\long\def\expsecond#1#2{\swaparg{#2}{#1}}-
+
+qui, apr\xE8s que \xA7\swaparg ait jou\xE9 son r\xF4le, donnerait \xAB\verb|#1{#2}|\xBB. Pour que le premier token de \verb|#2| soit 1-d\xE9velopp\xE9, il faut placer des \verb|\expandafter| dans le texte de remplacement de \xA7\expsecond pour provoquer ce d\xE9veloppement. Cela donne :
+
+\centrecode-\long\def\swaparg#1#2{#2{#1}}
+\long\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}-
+\end{exercice}
+
+\begin{exercice}
+Combien de d\xE9veloppements doit subir \xA7\expsecond\verb-{<arg1>}{<arg2>}- pour que le code qui soit effectivement \xE0 lire soit \verb-<arg1>{*<arg2>}- ?
+
+Placer correctement des \verb|\expandafter| dans le 2\ieme{} ligne de ce code
+
+\centrecode-\def\X{Bonjour}
+\>\expsecond{\X}{\X}<-
+
+pour qu'il affiche \xAB \string\X{} Bonjour \xBB. La macro \verb|\>|, programm\xE9e \xE0 la page~\pageref{macro.>}, affiche tel quel le code qu'elle rencontre jusqu'au prochain \verb|<|.
+\solution
+D\xE9veloppons \xA7\expsecond\verb-{<arg1>}{<arg2>}- comme le fait \TeX{} :
+\begin{enumerate}
+	\item  \verb-\expandafter\swaparg\expandafter{<arg2>}{<arg1>}-
+	\item \verb-\swaparg{*<arg2>}{<arg1>}- (les \verb|\expandafter| ont jou\xE9 leur r\xF4le)
+	\item \verb-<arg1>{*<arg2>}-
+\end{enumerate}
+Il faut donc 3 d\xE9veloppements.
+\medskip
+
+Dans \xAB\verb-\>\expsecond{\X}{\X}<-\xBB, si l'on veut 3-d\xE9velopper \xA7\expsecond, il faudra mettre $2^3-1=7$ \verb-\expandafter- devant \verb-\>- :
+
+\showcode/\long\def\swaparg#1#2{#2{#1}}\xA4\xA7*\swaparg\idx*\long\xA4
+\long\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}\xA4\xA7*\expsecond\idx*\long\xA4
+\def\X{Bonjour}
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\>\expsecond{\X}{\X}<\xA4\xA7*\expsecond\xA4/
+\end{exercice}
+
+\begin{exercice}
+Dans quels cas \xA7\expsecond ne fonctionne pas comme attendu ?
+\solution
+Si l'on examine la d\xE9finition
+
+\centrecode-\long\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}-\xA7*\expsecond
+
+on constate que le 1-d\xE9veloppement de l'argument \verb|#2| a lieu alors que cet argument est d\xE9plac\xE9 et n'est plus en dernier, c'est-\xE0-dire qu'il ne pr\xE9c\xE8de pas le code qui suit. D\xE8s lors, si cet argument doit agir sur le code qui suit (avec \xA7\gobone, \xA7\identity, \xA7\firstoftwo ou \xA7\secondoftwo), il n'est plus en mesure de le faire. Dans l'exemple ci-dessous, on souhaite 1-d\xE9velopper \xA7\gobone pour donner \xE0 \verb|\foo| le texte de remplacement \xAB\verb|B|\xBB :
+
+\errcode/\expsecond{\def\foo}\secondoftwo{A}{B}\xA4\xA7*\expsecond\xA7*\secondoftwo\xA4/{Argument of \texttt{\string\secondoftwo} has an extra \char`\}}
+
+Le 2\ieme{} argument de \xA7\expsecond est \xA7\secondoftwo donc, apr\xE8s avoir 1-d\xE9velopp\xE9 \xA7\expsecond dans \xAB\verb|\expsecond{\def\foo}\secondoftwo{A}{B}|\xBB, voici ce que l'on obtient :
+
+\centrecode-\expandafter\swaparg\expandafter{\secondoftwo}{\def\foo}-
+
+Lorsque \xA7\secondoftwo est 1-d\xE9velopp\xE9, en cherchant son premier argument, il voit \xAB\verb|}|\xBB et c'est l\xE0 que \TeX{} proteste car une accolade fermante ne peut pas \xEAtre le d\xE9but d'un argument.
+
+Pour que \xABB\xBB soit le texte de remplacement de \verb|\foo|, il aurait fallu que \xAB\verb|\secondoftwo{A}|\linebreak[1]\verb|{B}|\xBB soit le 2\ieme{} argument de \xA7\expsecond :
+
+\showcode/\expsecond{\def\foo}{\secondoftwo{A}{B}}\xA4\xA7*\expsecond\xA7*\secondoftwo\xA4
+\meaning\foo\xA4\idx\meaning\xA4/
+\end{exercice}\xA7*\expsecond[|)]\xA7*\swaparg[|)]
+
+La macro \xA7\expsecond peut \xEAtre utilis\xE9e si son premier argument est une macro :
+
+\centrecode-\expsecond\<macro>{<argument>}-
+
+\noindent Dans ce cas, \xA7\expsecond 1-d\xE9veloppe l'argument de la macro avant d'ex\xE9cuter la macro. C'est pourquoi la macro \xA7\expsecond a un alias \xAB\xA7\exparg\xBB d\xE9fini par \idx\let dont le nom sugg\xE8re davantage que l'argument d'une macro a \xE9t\xE9 d\xE9velopp\xE9.
+
+\begin{exercice}
+En reprenant le m\xEAme principe que \xA7\exparg, d\xE9finir une macro \xA7*\exptwoargs
+
+\centrecode-\exptwoargs\<macro>{argument 1}{argument 2}-
+
+\noindent qui 1-d\xE9veloppe les 2 premiers tokens des deux arguments avant de lancer la \verb|\<macro>|
+\solution
+Deux appels imbriqu\xE9s \xE0 \xA7\exparg conduisent au r\xE9sultat :
+
+\centrecode-\def\exptwoargs#1#2#3{\expsecond{\expsecond{#1}{#2}}{#3}}-
+
+\noindent Comme l'argument \verb|#3| se trouve une seule fois dans le texte de remplacement de la macro et \xE0 la fin de celui-ci, il est possible de ne pas le faire lire par \xA7\exptwoargs :
+
+\showcode/\def\exptwoargs#1#2{\expsecond{\expsecond{#1}{#2}}}\xA4\xA7*\exptwoargs\xA7*\expsecond\xA4
+\def\foo{Bonjour}\def\bar{ le monde}
+\def\displaytwoargs#1#2{\detokenize{#1#2}}% affiche tels quels les arguments
+\exptwoargs\displaytwoargs\foo\bar\xA4\xA7*\exptwoargs\xA4/
+\end{exercice}
+
+Une macro plus g\xE9n\xE9rale, capable de d\xE9velopper plusieurs arguments sera programm\xE9e plus loin (voir page~\pageref{eargs}).
+
+\section{La primitive \texttt{\textbackslash edef}}\idx*[|(]\edef
+On a vu que  \verb-\expandafter- permettait de contr\xF4ler finement la profondeur de d\xE9veloppement moyennant, c'est vrai, de longs et laborieux ponts d'\idx[|)]\expandafter. Mais il existe des endroits o\xF9 \TeX{} d\xE9veloppe au maximum\idx*[|(]{d\xE9veloppement maximal} ce qu'il rencontre. Attention, il s'agit bien d'un d\xE9veloppement et non pas d'une ex\xE9cution. Le plus c\xE9l\xE8bre de ces endroits est le texte de remplacement des macros d\xE9finies avec la primitive \verb|\edef|. Cette primitive fonctionne comme sa s\oe ur \verb-\def- sauf que tout ce qui se trouve \xE0 entre les accolades est d\xE9velopp\xE9 au maximum et ce qui en r\xE9sulte est le \idx{texte de remplacement} de la macro d\xE9finie par \verb|\edef|. Essayons :
+
+\showcode/\def\aa{Bonjour}\def\bb{\aa}
+\def\cc{ le monde}
+\edef\foo{\bb\cc}
+\meaning\foo\xA4\idx*\meaning\xA4/
+
+On constate que le texte de remplacement de \verb-\foo- contient le 2-d\xE9veloppement de \verb|\bb| et le 1-d\xE9veloppement de \verb|\cc|. Ces d\xE9veloppements sont les plus profonds que l'on puisse faire puisqu'ensuite on ne trouve plus que des lettres ou des espaces. Le texte de remplacement de \verb-\truc- est bien \xAB Bonjour le monde \xBB.
+
+Comme pour \verb-\def-, on peut aussi sp\xE9cifier qu'une macro d\xE9finie avec \verb|\edef| admet des arguments, et on utilise pour cela la m\xEAme syntaxe \verb|#<chiffre>|, aussi bien pour le \idx{texte de param\xE8tre} que pour le texte de remplacement. Le d\xE9veloppement maximal fait lors de la d\xE9finition concerne tout ce qui se trouve dans le \idx{texte de remplacement} \emph{\xE0 l'exception} des emplacements des arguments qui ont la syntaxe \verb|#<chiffre>|. Les arguments, qui seront lus plus tard lorsque la macro sera appel\xE9e, seront ins\xE9r\xE9s tels quels \xE0 la place de \verb|#<chiffre>| : ils ne sont donc pas soumis au d\xE9veloppement maximal.
+
+On peut le constater ici o\xF9 la macro \verb-\ee- est d\xE9finie avec un \verb-\edef- et admet un argument. \xC0 l'aide d'\verb-\expandafter-, on provoque le 1-d\xE9veloppement de la macro \verb-\ee- dont l'argument est la macro \verb-\dd-. On peut constater que cet argument \xAB\verb-\dd-\xBB reste non d\xE9velopp\xE9 bien qu'il soit l'argument d'une macro d\xE9finie avec \verb-\edef- :
+
+\showcode/\def\aa{Bonjour } \def\bb{\aa} \def\cc{le } \def\dd{ monde}
+\edef\ee#1{\bb\cc#1 !!!}
+\meaning\ee\par\xA4\idx*\meaning\xA4
+\expandafter\>\ee{\dd}</
+
+\begin{regle}
+La primitive \verb-\edef- a la m\xEAme syntaxe et les m\xEAmes actions que \verb-\def-, c'est-\xE0-dire qu'elle stocke un \idx[|etc]{texte de remplacement}\forbidindex{texte de remplacement} associ\xE9 \xE0 une \idx{s\xE9quence de contr\xF4le}. La diff\xE9rence r\xE9side dans le fait que la totalit\xE9 du texte de remplacement est d\xE9velopp\xE9e \emph{au maximum} avant que l'assignation soit faite.
+
+Le d\xE9veloppement s'applique au texte de remplacement \emph{hors arguments} symbolis\xE9s par \verb|#<chiffre>|. Ceux-ci, qu'ils soient d\xE9limit\xE9s ou pas, seront ins\xE9r\xE9s tels qu'ils seront lus dans le texte de remplacement (qui lui aura \xE9t\xE9 pr\xE9alablement d\xE9velopp\xE9).
+
+La primitive \idx\xdef effectue les m\xEAmes actions que \verb|\edef| sauf que la d\xE9finition faite est globale.
+\end{regle}
+
+\subsection{\texttt{\char`\\noexpand} pour contrer \texttt{\char`\\edef}}\idx*[|(]\noexpand
+Cette primitive \verb-\edef- se r\xE9v\xE8le fort utile, et rend de grands services. Mais dans son argument o\xF9 tout est d\xE9velopp\xE9 au maximum, on voudrait pouvoir bloquer le d\xE9veloppement d'une \idx{s\xE9quence de contr\xF4le}. Par exemple, si l'on \xE9crit
+
+\centrecode-\edef\foo{\aa\bb\cc}-
+
+\noindent comment laisser \verb-\aa- et \verb-\cc- se d\xE9velopper au maximum tout en bloquant le d\xE9veloppement de \verb-\bb- ? C'est l\xE0 qu'une nouvelle primitive entre en jeu, il s'agit de \verb-\noexpand-.
+
+\begin{regle}
+La primitive d\xE9veloppable \verb|\noexpand| bloque le d\xE9veloppement du token $x$ qui la suit. Elle a pour effet, lorsqu'elle se 1-d\xE9veloppe, d'\xEAtre le token $x$ lui-m\xEAme. Si $x$ est une s\xE9quence de contr\xF4le qui aurait \xE9t\xE9 d\xE9velopp\xE9e, $x$ est rendu temporairement \xE9gal \xE0 \verb|\relax|.
+\end{regle}
+
+\showcode|\def\foo{123xyz}
+a) signification du 1-d\xE9veloppement d'un \litterate-\noexpand- :\xA4\idx*\string\idx*\noexpand\xA7*\litterate\xA4
+   \expandafter\meaning\noexpand\foo\xA4\idx*\meaning\xA4
+
+b) ex\xE9cution d'un \litterate-\noexpand- : \noexpand\foo% identique \xE0 \relax
+
+c) 1-d\xE9veloppement de \litterate-\noexpand- dans le texte de remplacement de
+   \litterate-\bar- :\xA4\xA7*\litterate\xA4
+   \expandafter\def\expandafter\bar\expandafter{\noexpand\foo}
+   \meaning\bar\xA4\idx*\meaning\xA4|
+
+Le dernier cas montre qu'entre le moment du 1-d\xE9veloppement de \verb|\noexpand|\linebreak[1]\verb|\foo| et le moment o\xF9 \TeX{} lit ce 1-d\xE9veloppement, plusieurs choses sont faites (lecture et ex\xE9cution du \verb|\def| suivie de la lecture \verb|\bar| et de l'accolade ouvrante). Entre temps, le d\xE9veloppement initi\xE9 par le pont d'\verb|\expandafter| s'est arr\xEAt\xE9, signant la mort du \verb|\relax| temporaire qui est donc redevenu \verb|\foo|.
+\grandsaut
+
+Dans le code \xAB \verb-\edef\foo{\aa\bb\cc}-\xBB, tentons maintenant de bloquer le d\xE9veloppement de \verb|\bb| :
+
+\showcode/\def\aa{Bonjour}\def\bb{\aa}\def\cc{\bb}
+a) \edef\foo{\aa\noexpand\bb\cc}\meaning\foo  \qquad b) ex\xE9cution : \foo\par\xA4\idx*\meaning\xA4
+c) \edef\foo{\aa\noexpand{\aa\cc}}\meaning\foo\qquad d) ex\xE9cution : \foo/
+
+Tout se passe comme pr\xE9vu au a) pour la premi\xE8re d\xE9finition de \verb-\foo- avec \verb-\edef- : le \verb-\noexpand- qui pr\xE9c\xE8de \verb-\bb- emp\xEAche bien son d\xE9veloppement.
+
+\xC0 la deuxi\xE8me ligne (cas c), on a tent\xE9 bien maladroitement de bloquer le d\xE9veloppement de ce qui se trouve entre accolades. Ceci \xE9choue puisque \verb-\noexpand- bloque le d\xE9veloppement du \emph{token} qui suit et qui est dans ce cas \xAB\cidx\{\xBB. Cette accolade ouvrante n'a d'ailleurs nul besoin d'\xEAtre prot\xE9g\xE9e d'un d\xE9veloppement puisqu'elle n'est pas d\xE9veloppable (et elle se d\xE9veloppe donc en elle-m\xEAme). Pour bloquer le d\xE9veloppement de plusieurs s\xE9quences de contr\xF4le, il \emph{faut} mettre un \verb-\noexpand- devant chacune d'elles !
+
+\subsection{\texttt{\char`\\unexpanded} pour contrer \texttt{\char`\\edef}}
+Multiplier les \verb-\noexpand- et en \xE9crire autant qu'il y a de tokens \xE0 prot\xE9ger peut \xEAtre lourd, voire impossible si on ne connait pas le nombre de tokens lorsqu'on manipule l'argument d'une macro par exemple. Pour contourner cette difficult\xE9, on peut utiliser la primitive \idx\unexpanded de \eTeX{} dont le d\xE9veloppement est de bloquer le d\xE9veloppement du texte entre accolades qui suit la primitive.
+
+Voici deux fa\xE7ons de faire \xE9quivalentes, la premi\xE8re en pla\xE7ant un \verb|\noexpand| devant \verb|\bb| et \verb|\aa| la seconde en mettant ces deux tokens dans l'argument de la primitive \verb|\unexpanded| :
+
+\showcode/\def\aa{Bonjour}\def\bb{Au revoir}
+a) \edef\truc{\aa\noexpand\bb\noexpand\aa\bb}\meaning\truc \par\xA4\idx*\meaning\xA4
+b) \edef\truc{\aa\unexpanded{\bb\aa}\bb}\meaning\truc\xA4\idx*\meaning\xA4/\idx*[|)]\noexpand
+
+La primitive \idx\unexpanded, tout comme \idx\detokenize et d'autres, fait partie des primitives qui doivent \xEAtre suivies d'une accolade ouvrante. Ces primitives initient un d\xE9veloppement maximal jusqu'\xE0 ce qu'elles rencontrent une accolade ouvrante (voir r\xE8gle page~\pageref{primitive.suivie.par.accolade}). On peut donc intercaler un ou plusieurs \idx\expandafter entre ces primitives et l'accolade ouvrante de fa\xE7on \xE0 proc\xE9der au d\xE9veloppement du (ou des) premiers tokens du texte entre accolades.
+
+\subsection{\texttt{\char`\\the\char`\\toks\codeelement{nombre}} pour contrer  \texttt{\char`\\edef}}\idx*\toks
+Il existe un autre moyen qui ne fait pas appel \xE0 \eTeX{} et qui permet de bloquer le d\xE9veloppement dans un \verb|\edef|. Il s'agit du contenu d'un registre de tokens : dans le texte de remplacement d'un \verb|\edef|, le contenu d'un registre de tokens obtenu par le d\xE9veloppement de \idx\the\linebreak[1]\idx\toks\linebreak[1]\verb|<nombre>| (ou par \xAB\verb|\the|\linebreak[1]\verb|<nom d'un registre>|\xBB) n'est pas d\xE9velopp\xE9.
+
+Voici l'exemple pr\xE9c\xE9dent trait\xE9 avec un registre \xE0 token (ici, nous prenons le registre \no0) :
+
+\showcode|\def\aa{Bonjour}\def\bb{Au revoir}
+\toks0={\aa\bb}\xA4\idx*\toks\xA4
+\edef\foo{\aa\the\toks0 \bb}\xA4\idx*\toks\xA4
+\meaning\foo\xA4\idx*\meaning\xA4|
+
+\subsection{Prot\xE9ger une macro avec \texttt{\char`\\protected}}
+Tout comme on peut d\xE9clarer une macro \xAB\idx\long\xBB ou \xAB\idx\global\xBB lors de sa d\xE9finition, on peut aussi d\xE9clarer qu'on souhaite d\xE9finir une macro \xAB prot\xE9g\xE9e \xBB. On entend \xAB prot\xE9g\xE9e contre le d\xE9veloppement maximal dans l'argument d'une primitive \xBB. Pour ce faire, il faut utiliser la primitive de \eTeX {} \xAB\idx\protected\xBB et la placer avant le \verb|\def| (ou \verb|\edef|) qui effectue la d\xE9finition. La macro ainsi d\xE9finie ne se d\xE9veloppera pas dans un \verb|\edef| :
+
+\showcode/\def\aa{Bonjour}
+\protected\def\bb{ le}% \ bb est prot\xE9g\xE9e !\xA4\idx*\protected\xA4
+\def\cc{ monde}
+
+\edef\foo{\aa\bb\cc}
+Signification de \string\foo~: \meaning\foo \par\xA4\idx*\meaning\xA4
+Ex\xE9cution de \string\foo~: \foo\xA4\idx*\string\xA4/
+
+Il faut bien comprendre que la macro est prot\xE9g\xE9e \verb|\bb|d'un d\xE9veloppement est maximal, mais pas de l'action de \verb|\expandafter|. Voici comment on peut 1-d\xE9velopper \verb|\bb| dans le texte de remplacement de \verb|\edef| avec un \verb|\expandafter| :
+
+\showcode/\def\aa{Bonjour}
+\protected\def\bb{ le}\xA4\idx*\protected\xA4
+\def\cc{ monde}
+
+\edef\foo{\expandafter\aa\bb\cc}% le \expandafter 1-d\xE9veloppe \bb
+\meaning\foo/
+
+\subsection{Les moyens de bloquer le d\xE9veloppement maximal}\label{bloquer.developpement.maximum}
+Il faut savoir est que certaines primitives (\idx\edef, \idx\xdef, \idx\csname\linebreak[1]\verb|...|\linebreak[1]\idx\endcsname que nous connaissons mais aussi \idx\message, \idx\write et \idx\errmessage que nous verrons plus tard) d\xE9veloppent au maximum ce qui est dans leur argument\footnote{Il y a aussi \texttt{\char`\\special}, \texttt{\char`\\mark} et \texttt{\char`\\marks} qui ne seront pas \xE9tudi\xE9es dans ce livre. Pour \xEAtre complet, il faut signaler que  le d\xE9veloppement maximal est aussi en marche dans un alignement lorsque \TeX{} recherche un \texttt{\char`\\omit} ou un \texttt{\char`\\noalign}.}. Les m\xE9thodes pour contrer ce d\xE9veloppement maximal valent aussi bien pour \verb|\edef| que pour n'importe quelle autre de ces primitives. Voici le r\xE9sum\xE9 des m\xE9thodes que nous avons vues :
+
+\begin{regle}
+Il existe 4 moyens de bloquer le d\xE9veloppement maximal dans les arguments de certaines primitives :
+\begin{enumerate}
+	\item mettre un \idx\noexpand devant chaque token dont on veut bloquer le d\xE9veloppement;
+	\item placer les tokens dont on veut bloquer le d\xE9veloppement dans l'argument de la primitive \idx\unexpanded de \eTeX{};
+	\item stocker au pr\xE9alable tous les tokens dont on veut bloquer le d\xE9veloppement dans un \verb|<registre de token>|\idx*{registre!token} et \xE9crire dans l'argument de la primitive \idx\the\verb|<registre de token>|;
+	\item lorsqu'on d\xE9finit une macro, il est possible de faire pr\xE9c\xE9der le \verb|\def| de la primitive \idx\protected de \eTeX{} pour emp\xEAcher le d\xE9veloppement maximal de cette macro.
+\end{enumerate}
+\end{regle}\idx*[|)]\edef{}\idx*[|)]{d\xE9veloppement maximal}
+
+\section{Code purement d\xE9veloppable}\idx*[|(]{code purement d\xE9veloppable}
+On pourrait penser que la primitive \verb|\edef| peut simuler une \xAB ex\xE9cution \xBB pour mettre dans la \idx{s\xE9quence de contr\xF4le} qu'elle d\xE9finit le \xAB r\xE9sultat \xBB de l'ex\xE9cution du \idx{texte de remplacement}\footnote{On peut stocker l'affichage r\xE9sultant d'un code arbitraire \xE0 l'aide des registres de boites que nous verrons plus tard.}. Il s'agit g\xE9n\xE9ralement d'une erreur, et pour comprendre pourquoi, il faut parler de ce qu'est du \xAB code purement d\xE9veloppable \xBB.
+
+Afin de mieux comprendre de quoi il s'agit, prenons un exemple simple, n'ayant aucun int\xE9r\xEAt si ce n'est p\xE9dagogique. Supposons que la macro \verb|\foo| a comme texte de remplacement \xABabc\xBB, ce qui suppose qu'un \verb|\def\foo{abc}| a \xE9t\xE9 rencontr\xE9 auparavant. Voici un code \xE9l\xE9mentaire qui d\xE9finit une macro \verb|\foo| et qui l'ex\xE9cute :
+
+\showcode/\def\foo{Bonjour}% d\xE9finition
+\foo% ex\xE9cution/
+
+Ce code de deux lignes n'est pas purement d\xE9veloppable. Essayons de comprendre pourquoi en le mettant dans un \verb|\edef| pour d\xE9finir la macro \verb|\bar| :
+
+\centrecode-\edef\bar{\def\foo{Bonjour}\foo}-
+
+Voici ce que va faire \TeX{} lorsqu'il va d\xE9velopper au maximum le code dans le texte de remplacement de \verb|\edef| :
+
+\begin{enumerate}
+	\item la primitive non d\xE9veloppable \verb|\def| se d\xE9veloppe en elle-m\xEAme et reste donc inchang\xE9e ;
+	\item les deux occurrences de \verb|\foo| vont \xEAtre d\xE9velopp\xE9es et donc remplac\xE9es par \xAB abc \xBB.
+\end{enumerate}
+
+Le texte de remplacement de \verb|\bar| sera donc :
+
+\centrecode-\def abc{Bonjour}abc-
+
+V\xE9rifions-le :
+
+\showcode/\def\foo{abc}
+\edef\bar{\def\foo{Bonjour}\foo}
+\meaning\bar\xA4\idx*\meaning\xA4/
+
+Ce texte de remplacement comporte une erreur, car apr\xE8s un \verb|\def|, on \emph{doit} trouver une \idx{s\xE9quence de contr\xF4le} (et non pas des caract\xE8res normaux comme a, b et c). Mais cette erreur n'apparait pas lors de la d\xE9finition de\verb|\bar| car \TeX{} effectue les assignations sans proc\xE9der \xE0 l'analyse du texte de remplacement. Ce n'est que si l'on cherche \xE0 ex\xE9cuter la macro \verb|\bar|, et donc \xE0 ex\xE9cuter son texte de remplacement que \TeX {} \xE9mettra le message d'erreur \xAB \texttt{Missing control sequence} \xBB.
+
+\begin{exercice}
+D\xE9crire ce qui se passerait si l'on \xE9crivait le code ci-dessous alors que la macro \verb|\foo| n'est pas d\xE9finie.
+
+\centrecode-\edef\bar{\def\foo{Bonjour}\foo}-
+
+\solution
+
+Lors du d\xE9veloppement maximal de \verb|\foo|, celle-ci n'\xE9tant pas d\xE9finie, \TeX{} \xE9mettrait le message d'erreur \xAB\texttt{Undefined
+ control sequence}\xBB.
+\end{exercice}
+
+La conclusion est donc sans appel : que \verb|\foo| soit d\xE9finie ou pas, le code n'est pas purement d\xE9veloppable. On pourrait r\xE9torquer que pour ce code soit purement d\xE9veloppable, il suffirait de bloquer le d\xE9veloppement de \verb|\foo| en se servant de la primitive \idx\noexpand :
+
+\showcode/\def\foo{abc}
+\edef\bar{\def\noexpand\foo{Bonjour}\noexpand\foo}\xA4\idx*\noexpand\xA4
+Signification : \meaning\bar\par\xA4\idx*\meaning\xA4
+Ex\xE9cution : \bar/
+
+Peut-on dire que le code, enrichi de \idx\noexpand, est purement d\xE9veloppable ? En fait, tout d\xE9pend de ce que l'on attendait ! Si l'on voulait simplement construire un code ex\xE9cutable stock\xE9 dans une macro, alors oui. Mais dans la grande majorit\xE9 des cas, on attend qu'un code purement d\xE9veloppable se r\xE9duise, lors de son d\xE9veloppement maximal, aux caract\xE8res affich\xE9s si ce code \xE9tait ex\xE9cut\xE9.
+
+\begin{regle}
+Un code est purement d\xE9veloppable si son d\xE9veloppement maximal se r\xE9duit aux caract\xE8res qui auraient \xE9t\xE9 affich\xE9s s'il avait \xE9t\xE9 ex\xE9cut\xE9 par \TeX.
+
+Dans la majorit\xE9 des cas, un tel code ne doit \xEAtre constitu\xE9 que caract\xE8res (ceux que l'on souhaite dans l'affichage final) ainsi que de s\xE9quences de contr\xF4le ou caract\xE8res actifs \emph{d\xE9veloppables}. Citons :
+\begin{itemize}
+	\item du c\xF4t\xE9 des primitives : \idx\expandafter, \idx\number, \idx\the, \idx\string ainsi que les primitives de \eTeX{} \idx\detokenize et \idx\unexpanded. Tous les tests de \TeX{} que nous verrons plus tard sont d\xE9veloppables. Il y a aussi deux primitives de \eTeX{}, \idx\numexpr et \idx\dimexpr qui seront \xE9tudi\xE9es dans la partie suivante;
+	\item les macros d\xE9finies par l'utilisateur, qu'elles soient \xE0 arguments d\xE9limit\xE9s ou pas, pourvu que leur d\xE9veloppement maximal soit constitu\xE9 des caract\xE8res que l'on souhaite dans l'affichage final.
+\end{itemize}
+\end{regle}\idx*[|)]{code purement d\xE9veloppable}
+
+\section{Propager le d\xE9veloppement}
+\subsection{Lier des zones de d\xE9veloppement maximal}
+Dans certaines zones bien sp\xE9cifiques, le d\xE9veloppement est maximal\idx*{d\xE9veloppement maximal} et donc, dans ces zones, le code doit \xEAtre purement d\xE9veloppable.
+
+L'expression \xAB propager le d\xE9veloppement \xBB signifie mettre en \oe uvre des m\xE9thodes pour que ces zones de d\xE9veloppement maximal se transmettent de proche en proche le d\xE9veloppement. Le but est de d\xE9velopper des territoires tr\xE8s \xE9loign\xE9s de l'endroit o\xF9 le premier d\xE9veloppement a eu lieu.
+
+Parfois, du code \TeX{} est constitu\xE9 de zones de d\xE9veloppement maximal entrecoup\xE9es de zones \xAB normales \xBB o\xF9 ce d\xE9veloppement maximal n'existe pas. Le sch\xE9ma ci-dessous repr\xE9sente une de ces situations o\xF9 les zones de d\xE9veloppement maximal sont encadr\xE9es et les tokens des zones normales sont repr\xE9sent\xE9s par \xAB$\ast$\xBB. La t\xEAte de lecture de \TeX{} est repr\xE9sent\xE9e par \TeXhead{} :
+
+\begin{centrage}
+\small\fboxsep0pt
+\TeXhead$\ast$\fbox{\strut\kern1.5cm }$\ast$\fbox{\strut\kern1.5cm }$\ast\ast$\fbox{\strut\kern1.5cm }$\ast x$
+\end{centrage}
+
+Il est possible, sans d\xE9placer la t\xEAte de lecture, de 1-d\xE9velopper le token $x$. Pour cela, on va amorcer le d\xE9veloppement de la premi\xE8re zone de d\xE9veloppement maximal en mettant un \idx\expandafter juste avant le premier token \xAB$\ast$\xBB. Par la suite, il faudra exporter le d\xE9veloppement hors des zones encadr\xE9es \xE0 l'aide d'un \verb|\expandafter| plac\xE9 en derni\xE8re position. Un pont d'\verb|\expandafter| prend ensuite le relai dans la zone normale pour communiquer le d\xE9veloppement \xE0 la zone encadr\xE9e suivante. \xC0 la fin de la derni\xE8re zone, un pont d'\verb|\expandafter| permettra d'atteindre le token $x$ pour le 1-d\xE9velopper. En notant \xAB$\bullet$\xBB la primitive \verb|\expandafter|, voici ce que devient le sch\xE9ma :
+
+\begin{centrage}
+\small\fboxsep0pt
+\TeXhead$\bullet\ast$\fbox{\strut\kern1.5cm $\bullet$}$\bullet\ast$\fbox{\strut\kern1.5cm $\bullet$}$\bullet\ast${}$\bullet\ast$\fbox{\strut\kern1.5cm $\bullet$}$\bullet\ast${}$x$
+\end{centrage}
+
+\begin{exercice}
+\Qu e faudrait-il modifier dans ce sch\xE9ma pour provoquer le 2-d\xE9veloppement du token $x$ ?
+
+\solution
+Tout restant \xE9gal par ailleurs, il faut initier un pont d'\verb|\expandafter| \xE0 deux passes \xE0 la fin de la derni\xE8re zone de d\xE9veloppement maximal, c'est-\xE0-dire mettre 3 \idx\expandafter au lieu d'un seul :
+
+\begin{centrage}
+\small\fboxsep0pt
+\TeXhead$\bullet\ast$\fbox{\strut\kern1.5cm $\bullet$}$\bullet\ast$\fbox{\strut\kern1.5cm $\bullet$}$\bullet\ast${}$\bullet\ast$\fbox{\strut\kern1.5cm $\bullet${}$\bullet${}$\bullet$}$\bullet${}$\bullet${}$\bullet\ast${}$x$
+\end{centrage}
+\end{exercice}
+
+\subsection{\xC9tude d'un cas}
+Pour illustrer ce propos, passons \xE0 un cas plus concret, quoiqu'encore tr\xE8s th\xE9orique. Supposons qu'avant de lire les macros \verb-\foo- et \verb-\bar-, nous devions provoquer le 2-d\xE9veloppement de la macro \verb-\wee- et le 1-d\xE9veloppement de \verb-\fin- dans le code suivant :
+
+\centrecode-\foo\bar\wee\fin-
+
+\noindent Le nombre d'\idx\expandafter n\xE9cessaires est assez important. Essayons de les compter ! Pla\xE7ons mentalement les \verb|\expandafter| pour provoquer tour \xE0 tour le d\xE9veloppement des macros prises \emph{de gauche \xE0 droite}, c'est-\xE0-dire que nous allons d'abord chercher \xE0 d\xE9velopper \verb|\wee| qui est la plus \xE0 gauche des deux macros. Ensuite, nous partirons du code obtenu et chercherons \xE0 d\xE9velopper \verb|\fin|.
+
+Pour 2-d\xE9velopper \verb|\wee|, il faut placer $2^2-1=3$ \idx\expandafter devant chaque token qui la pr\xE9c\xE8de ce qui fait $3\times2=6$ \idx\expandafter, not\xE9s $\bullet$:
+
+\begin{centrage}
+\small$\bullet\bullet\bullet$\litterate-\foo-$\bullet\bullet\bullet$\litterate-\bar\wee\fin-
+\end{centrage}
+
+\noindent Dans ce code, le nombre de tokens qui pr\xE9c\xE8dent \verb-\fin- devient \xE9gal \xE0 9 : nous avons les 6 \idx\expandafter que nous venons de placer et les 3 s\xE9quences de contr\xF4le \verb|\foo|, \verb|\bar| et \verb|\wee|. Pour 1-d\xE9velopper \verb|\fin|, il faut mettre un \verb|\expandafter| devant chaque token qui pr\xE9c\xE8de \verb|\fin| ce qui fait 9 \verb|\expandatfer| de plus et porte donc leur nombre total \xE0 $6+9=15$. Voici le code obtenu :
+
+\begin{centrage}
+\small$\bullet\bullet\bullet\bullet\bullet\bullet\bullet$\litterate-\foo-$\bullet\bullet\bullet\bullet\bullet\bullet\bullet$\litterate-\bar-$\bullet$\litterate-\wee\fin-
+\end{centrage}
+
+Venons-en maintenant aux zones de d\xE9veloppement maximal et au lieu d'\xE9crire directement le nom des 4 macros, aidons-nous de la paire \verb-\csname- et \verb-\endcsname- :
+
+\centrecode-\csname foo\expandafter\endcsname
+\csname bar\expandafter\endcsname
+\csname baz\expandafter\endcsname
+\csname fin\endcsname-
+
+Le r\xF4le des \idx\expandafter mis \xE0 chaque fin de zone de d\xE9veloppement maximal (sauf la derni\xE8re) est de transmettre le d\xE9veloppement en dehors de la zone de d\xE9veloppement maximal pour toucher le \idx\csname suivant qui commande \xE0 son tour le d\xE9veloppement maximal jusqu'au prochain \idx\endcsname. L'\verb|\expandafter| se trouvant en fin de zone transmet \xE0 son tour le d\xE9veloppement au \verb|\csname| suivant, et ainsi de suite jusqu'au dernier \verb-\endcsname- qui n'est pas pr\xE9c\xE9d\xE9 d'un \idx\expandafter et stoppe donc cet enchainement. La structure est clairement celle que l'on voyait dans le sch\xE9ma de la section pr\xE9c\xE9dente : externaliser le d\xE9veloppement pour d\xE9clencher le d\xE9veloppement d'une nouvelle zone de d\xE9veloppement maximal pour, en r\xE9it\xE9rant la man\oe uvre, transmettre tr\xE8s loin la flamme du d\xE9veloppement. Voici le sch\xE9ma qui traduirait cette situation (ici, aucun token ne se trouve entre les zones de d\xE9veloppement maximal) :
+
+\begin{centrage}
+\small\fboxsep0pt
+\TeXhead\fbox{\strut\kern1.5cm $\bullet$}\thinspace\fbox{\strut\kern1.5cm $\bullet$}\thinspace\fbox{\strut\kern1.5cm $\bullet$}\thinspace\fbox{\strut\kern1.5cm }
+\end{centrage}
+
+Le code donn\xE9 ci-dessus se 1-d\xE9veloppe en \xAB \verb-\foo\bar\wee\fin- \xBB. En voici la preuve :
+
+\showcode/\long\def\>#1<{\detokenize{#1}}\xA4\idx*\long\idx*\detokenize\xA4
+\expandafter\>% provoque le 1-d\xE9veloppement de :
+\csname foo\expandafter\endcsname\xA4\idx*\csname\idx*\endcsname\xA4
+\csname bar\expandafter\endcsname
+\csname wee\expandafter\endcsname
+\csname fin\endcsname</
+
+Dans le code ci-dessus, aucune \idx{s\xE9quence de contr\xF4le} n'est d\xE9velopp\xE9e. Pour provoquer le 1-d\xE9veloppement de \verb-\fin-, il suffit de mettre 3 \idx\expandafter apr\xE8s \xABwee\xBB au lieu d'un seul. En suivant le m\xEAme raisonnement, pour 2-d\xE9velopper \verb-\wee-, il faut 3-d\xE9velopper \verb-\csname-\linebreak[1] \verb-baz-\linebreak[1]\verb-\endcsname- et donc placer 7 \idx\expandafter apr\xE8s \xABbar\xBB. Cela donne le code :
+
+\centrecode-\csname foo\expandafter\endcsname
+\csname bar\expandafter\expandafter\expandafter\expandafter
+   \expandafter\expandafter\expandafter\endcsname
+\csname wee\expandafter\expandafter\expandafter\endcsname
+\csname fin\endcsname-
+
+\noindent Pour nous assurer que ce code fonctionne correctement, d\xE9finissons \verb-\wee- pour que son 2-d\xE9veloppement soit \xABXX\xBB et \verb-\fin- pour que son 1-d\xE9veloppement soit \xABYY\xBB :
+
+\showcode/\long\def\>#1<{\detokenize{#1}}\xA4\idx*\long\idx*\detokenize\xA4
+\def\fin{YY} \def\wee{\weeA} \def\weeA{XX}
+\expandafter\>%
+\csname foo\expandafter\endcsname\xA4\idx*\csname\idx*\endcsname\xA4
+\csname bar\expandafter\expandafter\expandafter\expandafter
+           \expandafter\expandafter\expandafter\endcsname
+\csname wee\expandafter\expandafter\expandafter\endcsname
+\csname fin\endcsname</
+
+Le premier \idx\expandafter qui pr\xE9c\xE8de \verb-\>- suffit \xE0 atteindre, de zone de d\xE9veloppement en zone de d\xE9veloppement, la toute fin de ce code avant m\xEAme que le premier nom de \idx{s\xE9quence de contr\xF4le} \verb-\foo- ne soit form\xE9.
+
+\begin{exercice}
+O\xF9 faut-il placer des \idx\expandafter dans \xAB \verb-\>\foo\bar\wee\fin<- \xBB pour obtenir la m\xEAme chose que dans l'exemple pr\xE9c\xE9dent ?
+\solution
+Il faut les 15 \idx\expandafter d\xE9j\xE0 vus sauf qu'il faut sauter le token \verb|\>| au d\xE9part. On a d\xE9j\xE0 calcul\xE9 qu'il faut 7 \idx\expandafter avant \verb-\foo-, il en faut \xE9galement 7 pour sauter \verb-\>- qui vient en premi\xE8re position. Cela nous fait $15+7=22$ \idx\expandafter (au lieu de 12 avec \idx\csname et \idx\endcsname) :
+
+\showcode/\long\def\>#1<{\detokenize{#1}}\xA4\idx*\long\idx*\detokenize\xA4
+\def\fin{YYY} \def\wee{\weeA} \def\weeA{XXX}
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\>%
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\foo
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\bar
+\expandafter\wee\fin</
+\end{exercice}
+
+\subsection{\Qu 'est-ce qu'un nombre ?}
+La notion de nombre (compris comme nombre \emph{entier}) \xE9tant \xE9troitement li\xE9e \xE0 celle de d\xE9veloppement, il est temps d'aborder ce sujet.\grandsaut
+
+Tout d'abord, il est faux de croire que lorsque \TeX{} ex\xE9cute le code
+
+\centrecode-le nombre 123 est impair-
+
+\noindent il \emph{lit} le nombre 123. Il ne fait qu'afficher s\xE9quentiellement les caract\xE8res \xAB1\xBB puis \xAB2\xBB et \xAB3\xBB sans pour autant que ces caract\xE8res ne soient isol\xE9s et analys\xE9s comme un tout formant un nombre entier. Pour que \TeX{} d\xE9clenche la lecture d'un nombre, il faut qu'il se trouve \xE0 un endroit o\xF9 il s'attend \xE0 en lire un.
+
+Nous avons d\xE9j\xE0 rencontr\xE9 plusieurs cas o\xF9 \TeX{} doit lire un nombre. C'est le cas pour les primitives \verb|\catcode|, \idx\lccode et \idx\uccode dont la syntaxe compl\xE8te est
+
+\begin{centrage}
+	\small$\left.\vcenter{\hbox{\verb|\catcode|}\par\hbox{\verb|\lccode|}\par\hbox{\verb|\uccode|}}\right\}$\verb-<nombre>= <nombre>-
+\end{centrage}
+
+\noindent o\xF9 le signe \verb|=| et l'espace qui le suit sont facultatifs.
+
+Nous avons vu qu'apr\xE8s la primitive \idx\toks, \TeX{} attend le \verb|<nombre>| correspondant au registre de tokens auquel on veut acc\xE9der. Nous savons \xE9galement qu'apr\xE8s la primitive \verb|\number|, \TeX{} s'attend \xE0 lire un nombre pour le convertir en chiffres arabes et en base 10. Un \verb|<nombre>| est \xE9galement attendu apr\xE8s la primitive \idx\char et le tout se traduit par l'affichage du caract\xE8re dont le code de caract\xE8re est \verb|<nombre>|.
+
+Pour \xEAtre complet concernant les caract\xE8res affich\xE9s via \idx\char, il est possible d'utiliser la primitive \idx\chardef dont la syntaxe est 
+
+\centrecode-\chardef\<macro>= <nombre>-
+
+\noindent Comme pour \verb|\catcode|, \idx\lccode et \idx\uccode, le signe \xAB=\xBB et l'espace qui le suit sont facultatifs. L'action qu'effectue ce code est de rendre la \verb|\<macro>| \xE9quivalente \xE0 \verb|\char<nombre>|. L'\xE9quivalence dont il est question ici ressemble \xE0 celle effectu\xE9e avec \verb|\let|. Ainsi, si on \xE9crit :
+
+\centrecode-\chardef\foo= 65-
+
+\noindent alors, la macro \verb|\foo| sera \xE9quivalente \xE0 \idx\char\verb|65| et produira un \xABA\xBB \xE0 l'affichage.
+
+Une \verb|\<macro>| d\xE9finie avec \idx\chardef rev\xEAt une dualit\xE9 int\xE9ressante : lorsque \TeX{} s'attend \xE0 lire un nombre, cette \verb|\<macro>| est alors comprise comme un nombre. Avec la macro \verb|\foo| ci-dessus, le nombre lu serait 65.
+
+\showcode/\chardef\foo65 \xA4\idx*\chardef\xA4
+a) |\foo|\qquad % employ\xE9e seule, \foo affiche un A\xA4\idx*\qquad\xA4
+b) |\number\foo|\qquad % si TeX lit un nombre, \foo est le nombre 65\xA4\idx*\number\xA4/
+
+Comme il n'y a que 256 caract\xE8res possibles\footnote{Pour les moteurs 8 bits, car les moteurs \utf en ont beaucoup plus.}, les primitives \idx\char et \idx\chardef ne peuvent prendre en compte que des nombres compris entre 0 et 255. Le mode math\xE9matique\idx*{mode!math\xE9matique} requiert d'afficher beaucoup plus de caract\xE8res que ces 256, aussi il existe les primitives \idx\mathchar et \idx\mathchardef qui sont au mode math\xE9matique\idx*{mode!math\xE9matique} ce que sont \idx\char et \idx\chardef au mode texte. Le caract\xE8re dual d'une macro d\xE9finie par \idx\mathchardef existe sauf que le nombre qu'elle peut repr\xE9senter est compris entre 0 et \numprint{32767}\footnote{Voir le \TeX book, page 181.} et lorsqu'elle est utilis\xE9e pour afficher un caract\xE8re, le mode math\xE9matique doit \xEAtre en vigueur.
+
+\showcode/\mathchardef\foo4944 \xA4\idx*\mathchardef\xA4
+a) |$\foo$|\qquad % en mode math, affiche le signe "somme" (uniquement en mode maths)\xA4\idx*\qquad\xA4
+b) |\number\foo|\qquad % si TeX lit un nombre, \foo est 4944\xA4\idx*\number\xA4/
+
+Il est temps de donner la d\xE9finition d'un nombre et montrer en quoi elle est li\xE9e au d\xE9veloppement.
+
+\label{definition.entier}\begin{regle}
+\relax\idx*{nombre!d\xE9finition}Un \xABnombre\xBB est un entier relatif compris entre $-2^{31}+1$ et $2^{31}-1$, c'est-\xE0-dire entre $-\numprint{2147483647}$ et $\numprint{2147483647}$. Tout nombre hors de cet intervalle provoque une erreur de compilation.
+
+Lorsque \TeX{} s'attend \xE0 lire un nombre, il entre dans une phase de d\xE9veloppement maximal. Dans les r\xE9sidus de ce d\xE9veloppement, il cherche tout d'abord une s\xE9rie de signes optionnels de catcode 12 : \xAB\verb|+|\xBB et \xAB\verb|-|\xBB. Le signe du nombre final d\xE9pendra de la parit\xE9 du nombre de signes \xAB\verb|-|\xBB lus au total. Ensuite, plusieurs cas peuvent se pr\xE9senter :
+\begin{enumerate}
+	\item le nombre est explicitement \xE9crit en
+	
+	\begin{itemize}[topsep=0pt]
+		\item base 8 sous la forme \verb|'<signes>|;
+		\item base 10 sous la forme \verb|<signes>|;
+		\item base 16 sous la forme \verb|"<signes>|,
+	\end{itemize}
+
+	o\xF9 les \verb|<signes>| sont une suite de chiffres de catcode 12 allant de \verb|0| \xE0 \verb|7| pour la base 8, de \verb|0| \xE0 \verb|9| pour la base 10 et pour la base 16, de \verb|0| \xE0 \verb|9| auxquels s'ajoutent les lettres \emph{majuscules} de catcode 11 ou 12 allant de \verb|A| \xE0 \verb|F|.
+	
+	\TeX{} stoppe la lecture du nombre au premier token qui n'est pas un \verb|<signe>| valide. Si ce token est un espace, il sera absorb\xE9. Le nombre lu comprend donc la plus longue s\xE9rie de \verb|<signes>| valides possible;
+	\item un \xAB compteur \xBB se pr\xE9sente (nous verrons les compteurs plus loin). Le nombre qu'il contient est lu et la lecture du nombre est stopp\xE9e;
+	\item un \xAB registre de dimension \xBB se pr\xE9sente. Dans ce cas, la dimension est convertie en entier (nous verrons comment plus loin) et la lecture du nombre s'ach\xE8ve;
+	\item une \idx{s\xE9quence de contr\xF4le} d\xE9finie avec \idx\chardef pour les nombres compris entre 0 \xE0 255 ou avec \idx\mathchardef pour ceux compris entre 0 \xE0 32767 se pr\xE9sente, le nombre correspondant est lu et la lecture du nombre est stopp\xE9e;
+	\item un nombre \xE9crit sous la forme \verb|`<car>| ou \verb|`\<car>| se pr\xE9sente, o\xF9 \xAB\verb|`|\xBB est l'apostrophe inverse. Le nombre lu est le code de caract\xE8re de \verb|<car>|. Le \emph{d\xE9veloppement maximal se poursuit} jusqu'au premier token non d\xE9veloppable qui signe la fin de la lecture du nombre. \emph{Si ce token est un espace, il est absorb\xE9}.
+\end{enumerate}
+\end{regle}
+
+Plain-\TeX{} d\xE9finit la \idx{s\xE9quence de contr\xF4le} \idx\z@ comme \xE9tant un registre de dimension \xE9gal \xE0 la dimension nulle \verb|0pt|. Cette \idx{s\xE9quence de contr\xF4le} est souvent employ\xE9e en programmation, car elle pr\xE9sente 3 avantages :
+
+\begin{enumerate}
+	\item elle est convertie en l'entier 0 lorsque \TeX{} lit un nombre entier;
+	\item elle est la dimension \verb|0pt| lorsque \TeX{} lit une dimension;
+	\item dans les deux cas pr\xE9c\xE9dents, elle stoppe la lecture et le d\xE9veloppement maximal.
+\end{enumerate}
+
+La primitive \idx\number est d\xE9veloppable et son 1-d\xE9veloppement provoque un travail assez cons\xE9quent : lecture du nombre selon la r\xE8gle vue ci-dessus et conversion de ce nombre en base 10 sous la forme la plus simple en tokens de catcode 12. Par \xABforme la plus simple\xBB, on entend que le signe du nombre n'est donn\xE9 que s'il est n\xE9gatif et que les 0 inutiles de gauche sont supprim\xE9s si le nombre \xE9tait explicitement \xE9crit.
+
+Lorsque \idx\the est imm\xE9diatement suivi d'un compteur, d'un registre de dimension ou d'une s\xE9quence de contr\xF4le d\xE9finie avec  \idx\chardef ou \idx\mathchardef, elle se comporte comme \idx\number.
+
+Les compteurs, les registres de dimensions et les s\xE9quences de contr\xF4le d\xE9finies avec \idx\chardef ou \idx\mathchardef sont des repr\xE9sentations \emph{internes} d'entiers qui n\xE9cessitent une primitive d\xE9veloppable (\idx\the ou \idx\number) pour obtenir les chiffres formant ce nombre en base 10. C'est donc une erreur que de les en d\xE9pourvoir pour les afficher.
+
+\subsection{Nombres romains}
+Tout comme \idx\number et \idx\the sont capable de produire des nombres arabes, la primitive \idx\romannumeral produit des nombres romains.
+
+\begin{regle}
+La primitive \idx\romannumeral doit \xEAtre suivie d'un \verb|<nombre>| valide.
+
+Son 1-d\xE9veloppement est
+\begin{itemize}
+	\item l'\xE9criture en chiffres romains de catcode 12 si le \verb|<nombre>| est strictement positif;
+	\item vide si le nombre est n\xE9gatif ou nul.
+\end{itemize}
+
+Si le \verb|<nombre>| est sup\xE9rieur \xE0 1000, la lettre \xAB\verb|m|\xBB de catcode 12 sera produite autant de fois qu'il y a de milliers dans le nombre.
+\end{regle}
+
+Nous faisons fonctionner ici la primitive \idx\romannumeral en l'encadrant des caract\xE8res \xAB\verb|"|\xBB pour mettre en \xE9vidence que les espaces qui suivent les nombres disparaissent bien. V\xE9rifions \xE9galement que le d\xE9veloppement maximal a bien lieu avec les macros \verb-\foo- et \verb-\bar- :
+
+\showcode|a) "\romannumeral 27 "\quad\xA4\idx*\romannumeral\idx*\quad\xA4
+b) "\romannumeral 4687 "\quad
+c) "\romannumeral 0 "\quad% 0 donc d\xE9veloppement vide
+d) "\romannumeral -2014 "\quad% n\xE9gatif donc d\xE9veloppement vide
+e) \def\foo{7}\def\bar{\foo}%
+   "\romannumeral \foo\foo\bar"\quad% 777
+f) "\romannumeral 1\bar8\foo"\quad% 1787
+g) "\romannumeral 1\bar8 \foo"% 178 (stopp\xE9 par l'espace) puis 7\xA4\idx*\quad\idx*\romannumeral\xA4|
+
+Remarquons la diff\xE9rence entre les cas f et g o\xF9 le simple espace en plus apr\xE8s \xAB8\xBB au cas g stoppe la lecture du nombre et le d\xE9veloppement maximal. On constate que cet espace est absorb\xE9, car aucun espace n'existe \xE0 l'affichage entre \xAB\verb|clxxviii|\xBB et \xAB7\xBB.
+
+\subsection{Le d\xE9veloppement de \texttt{\char`\\romannumeral}}\idx*[!d\xE9veloppement|(]\romannumeral
+La primitive \idx\romannumeral est tr\xE8s int\xE9ressante, car son 1-d\xE9veloppement d\xE9clenche un d\xE9veloppement maximal dont on peut contr\xF4ler la port\xE9e. Surtout, ce d\xE9veloppement maximal peut ne laisser aucune trace si le nombre que lit finalement \idx\romannumeral est n\xE9gatif ou nul.
+
+Si dans ce sch\xE9ma
+
+\begin{centrage}
+	\small\fboxsep1pt
+	\fboxrule0.4pt
+	\verb-\romannumeral-\fbox{\fboxsep0pt \fcolorbox{gray!60}{gray!60}{\strut\kern2.5cm }$x$\textvisiblespace}
+\end{centrage}
+
+\begin{enumerate}
+	\item la zone grise ne contient que des tokens purement d\xE9veloppables dont le d\xE9veloppement est vide;
+	\item $x$ est un nombre n\xE9gatif ou nul
+\end{enumerate}
+
+\noindent alors, 1-d\xE9velopper \idx\romannumeral revient \xE0 d\xE9velopper au maximum tous les tokens se trouvant dans la zone grise et \xE0 supprimer le nombre $x$ et l'espace qui le suit.
+
+La zone encadr\xE9e devient une zone de d\xE9veloppement maximal dont la port\xE9e est contr\xF4l\xE9e par le placement du nombre n\xE9gatif ou nul $x$.
+
+Certes, cela implique une contrainte forte : tous les tokens dans la zone grise doivent \xEAtre purement d\xE9veloppables et une fois ceci fait, ils ne doivent rien laisser. En pratique, cette zone grise contient des appels \xE0 des macros et des tests.
+\grandsaut
+
+Pour mettre en \xE9vidence l'utilit\xE9 d'une telle structure, reprenons l'exercice de la page~\pageref{expsecond} o\xF9 l'on a vu que \xA7\expsecond\verb-{<arg1>}{<arg2>}- devait se d\xE9velopper 3 fois pour que le code effectivement dans la pile soit \verb-<arg1>{*arg2}- (l'\xE9toile indique que le premier token de l'argument 2 est 1-d\xE9velopp\xE9). Nous avions calcul\xE9 qu'il fallait placer 7 \idx\expandafter devant \verb-\>- pour parvenir \xE0 nos fins :
+
+\showcode/\long\def\>#1<{\detokenize{#1}}\xA4\idx*\long\idx*\detokenize\xA4
+\def\swaparg#1#2{#2{#1}}\xA4\xA7*\swaparg\xA4
+\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}\xA4\xA7*\expsecond\xA7*\swaparg\xA4
+\def\X{Bonjour}
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\>\expsecond\X\X<\xA4\xA7*\expsecond\xA4/
+
+Avec \verb-\romannumeral-, un seul \verb|\expandafter| sera requis pour sauter \verb|\>| et provoquer le 1-d\xE9veloppement de \verb-\romannumeral- qui va tout d\xE9velopper au maximum et s'arr\xEAter au bon moment. Ce \emph{bon moment} sera juste avant le \verb|\X| observ\xE9 \xE0 l'affichage. Comme ce \verb|\X| est l'argument \verb|#2| de \xA7\swaparg, un simple \verb*|0 |, plac\xE9 avant cet argument \verb|#2| stoppe le d\xE9veloppement maximal initi\xE9 par \verb|\romannumeral| :
+
+\showcode/\long\def\>#1<{\detokenize{#1}}\xA4\idx*\long\idx*\detokenize\xA4
+\def\swaparg#1#2{0 #2{#1}}% le "0 " stoppe ici le d\xE9veloppement maximal\xA4\xA7*\swaparg\xA4
+\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}\xA4\xA7*\expsecond\xA7*\swaparg\xA4
+\def\X{Bonjour}
+\expandafter\>\romannumeral\expsecond\X\X<\xA4\idx*\romannumeral\xA7*\expsecond\xA4/
+
+\begin{exercice}
+\xC0 quel autre endroit aurait-on pu placer \xAB\verb*-0 -\xBB pour que le d\xE9veloppement se passe comme on le souhaite ?
+\solution
+On veut stopper la lecture du nombre juste avant l'argument \verb-#2- de la commande \xA7\swaparg. Cet argument est l'argument \verb-#1- de la commande \xA7\expsecond et il suffit donc de mettre \xAB\verb*-0 -\xBB au d\xE9but du premier argument de \xA7\expsecond lorsqu'elle est appel\xE9e.
+
+\showcode/\long\def\>#1<{\detokenize{#1}}\xA4\idx*\long\idx*\detokenize\xA4
+\def\swaparg#1#2{#2{#1}}\xA4\xA7*\swaparg\xA4
+\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}\xA4\xA7*\expsecond\xA7*\swaparg\xA4
+\def\X{Bonjour}
+\expandafter\>\romannumeral\expsecond{0 \X}\X<\xA4\idx*\romannumeral\xA7*\expsecond\xA4/
+
+Contrairement \xE0 celle de l'exemple pr\xE9c\xE9dent, cette m\xE9thode pr\xE9sente l'avantage de ne pas avoir \xE0 modifier les macros \xA7\swaparg et \xA7\expsecond.
+\medbreak
+
+On aurait donc remplacer \verb*|0 | par \idx\z@ avec l'avantage pour ce dernier de stopper la lecture du nombre sans avoir \xE0 ins\xE9rer un espace :
+
+\showcode/\long\def\>#1<{\detokenize{#1}}\xA4\idx*\long\idx*\detokenize\xA4
+\def\X{Bonjour}
+\catcode`\@=11
+\expandafter\>\romannumeral\expsecond{\z@\X}{\X}<\xA4\idx*\romannumeral\idx\z@\xA7*\expsecond\xA4
+\catcode`\@=12 /
+\end{exercice}\idx*{nombre}\idx*[!d\xE9veloppement|)]\romannumeral
+
+\section{Programmation d'une variable unidimensionnelle}
+Finissons ce chapitre en programmant une \xAB variable \xBB, constitu\xE9e de cellules qui auront chacune un nom et qui contiendront un code choisi par l'utilisateur. Il s'agit ici de copier les variables de type tableau (ou array) \xE0 une dimension qu'offrent la plupart des langages de programmation.
+
+Supposons que l'on veuille d\xE9finir la variable unidimensionnelle \verb-\foobar-. Pour d\xE9finir la variable et remplir les cases dont les noms sont \xAB\texttt 0\xBB, \xAB\texttt 1\xBB, \xAB\texttt 3\xBB et \xAB\texttt{toto}\xBB, on doit pouvoir \xE9crire :
+
+\centrecode-\newunivar\foobar\xA4\xA7*\newunivar\xA4
+\defunivar\foobar[0]{abcd}
+\defunivar\foobar[1]{1 23}
+\defunivar\foobar[3]{XY Z}
+\defunivar\foobar[toto]{Bonjour}\xA4\xA7*\defunivar\xA4-
+
+\noindent Et par la suite, il suffira que l'on \xE9crive \verb-\foobar[0]- pour que le code \xAB\verb|abcd|\xBB, contenu dans la cellule \xAB\verb|0|\xBB soit restitu\xE9 et ex\xE9cut\xE9.
+\grandsaut
+
+Passons maintenant \xE0 la m\xE9canique interne. Si la variable est \xAB\verb|\foobar|\xBB, d\xE9cidons que le contenu des cellules sera stock\xE9 dans des s\xE9quences de contr\xF4le auxiliaires. Par exemple, le code de la cellule \verb|0| sera contenu dans la macro  \verb-\-\boxtoken{\foobar[0]}. Autrement dit, le \emph{nom} de la macro doit \xEAtre constitu\xE9 des 10 caract\xE8res (inoffensifs) \boxtoken{ \unskip\textbackslash}, \boxtoken f, \boxtoken o, \boxtoken o, \boxtoken b, \boxtoken a, \boxtoken r, \boxtoken{[}, \boxtoken 0 et \boxtoken]. Pour former un tel nom, nous ferons appel \xE0 la paire \idx\csname\linebreak[1]\verb-...-\linebreak[1]\idx\endcsname.
+
+L'ordre \xAB\verb-\newunivar\foobar-\xBB doit donc d\xE9finir la macro \verb-\foobar- de cette fa\xE7on :
+
+\centrecode-\def\foobar[#1]{\csname\string\foobar[#1]\endcsname}-\idx*\string
+
+Si on place ce texte de remplacement dans la d\xE9finition de \xA7\newunivar, il suffit de remplacer \verb|\foobar| par l'argument \verb|#1| de \xA7\newunivar et de doubler les \xAB\verb|#|\xBB. La macro \xA7\newunivar sera donc d\xE9finie ainsi :
+
+\centrecode-\def\newunivar#1{\def#1[##1]{\csname\string#1[##1]\endcsname}}-\idx*\string\xA7*\newunivar
+
+\noindent On pourra ainsi appeler par la suite \verb-\foobar[0]- qui se 2-d\xE9veloppera en la macro \verb-\-\boxtoken{\foobar[0]} tout en offrant la protection, au cas o\xF9 la cellule n'a pas \xE9t\xE9 d\xE9finie, que la paire \verb-\csname-\linebreak[1]\verb-...-\linebreak[1]\verb-\endcsname- g\xE9n\xE8re l'inoffensif \idx\relax. Aucune erreur de compilation ne sera donc provoqu\xE9e en cas d'appel \xE0 une cellule non d\xE9finie.
+
+Pour la macro \xA7\defunivar\verb-\<macro>[<nom>]-, un \idx\expandafter forcera la formation de la \idx{s\xE9quence de contr\xF4le} avant que \verb-\def-, qui proc\xE8de l'assignation, ne voie cette \idx{s\xE9quence de contr\xF4le}. Par cons\xE9quent, \xA7\defunivar\verb-\foo[0]- doit avoir le texte de remplacement suivant :
+
+\centrecode-\expandafter\def\csname\string\foo[0]\endcsname-\idx*\string\xA7*\defunivar
+
+\noindent Et donc, \xA7\defunivar doit \xEAtre d\xE9finie comme suit :
+
+\centrecode-\def\defunivar#1[#2]{\expandafter\def\csname\string#1[#2]\endcsname}-\idx*\string\xA7*\defunivar
+
+\noindent ou encore, en utilisant \xA7\defname
+
+\centrecode-\def\defunivar#1[#2]{\defname{\string#1[#2]}}-
+
+\noindent Il est inutile de lire l'argument du \verb|\def| qui est le contenu de la cellule. En effet, comme on l'a d\xE9j\xE0 vu \xE0 la page~\pageref{argument.def}, lire cet argument serait redondant puisqu'il faudrait le placer entre accolades \xE0 la fin du texte de remplacement de \xA7\defunivar. Voici donc comment proc\xE9der :
+
+\showcode/\def\newunivar#1{\def#1[##1]{\csname\string#1[##1]\endcsname}}\xA4\xA7*\newunivar\idx*\string\xA4
+\def\defunivar#1[#2]{\defname{\string#1[#2]}}\xA4\xA7*\defunivar\idx*\string\xA7*\defname\xA4
+\newunivar\foobar\xA4\xA7*\newunivar\xA4
+\defunivar\foobar[0]{abcd}
+\defunivar\foobar[1]{1 23}
+\defunivar\foobar[3]{XY Z}\xA4\xA7*\defunivar\xA4
+Cellule 0 : \foobar[0]\par
+Cellule 1 : \foobar[1]\par
+Cellule 2 : \foobar[2]\par% cellule non d\xE9finie : \foobar[2] donne \relax
+Cellule 3 : \foobar[3]\bigbreak
+
+\newunivar\client\xA4\xA7*\newunivar\xA4
+\defunivar\client[nom]{M. Raymond {\sc  Tartempion}}\xA4\idx*\sc\xA4
+\defunivar\client[adr]{5 rue de la paix}
+\defunivar\client[cod_post]{75000}
+\defunivar\client[ville]{Paris}\xA4\xA7*\defunivar\xA4
+% fin des d\xE9finitions, affichage de l'adresse :
+\client[nom]\par
+\client[adr]\par
+\client[cod_post] \client[ville]/
+
+On remarque que la programmation de cette variable unidimensionnelle est ici, gr\xE2ce \xE0 la richesse et la puissance des instructions de \TeX{}, relativement facile et extr\xEAmement concise puisqu'elle tient en deux lignes !
+
+\begin{exercice}
+Comment modifier les macros \xA7\newunivar et \xA7\defunivar vues pr\xE9c\xE9demment pour que les cellules ne soient pas stock\xE9es dans la macro \verb-\-\boxtoken{\foobar[0]} mais dans la macro \verb-\-\boxtoken{foobar at 0} ?
+\solution
+Faisons la supposition fond\xE9e que \idx\escapechar d\xE9finit \xAB\verb|\|\xBB comme \idx{caract\xE8re d'\xE9chappement}. Lorsque \idx\string est d\xE9velopp\xE9e \xE0 l'int\xE9rieur de \verb-\csname-\linebreak[1]\verb-...-\linebreak[1]\verb-\endcsname-, il con\-vertit le token \boxtoken{\foobar} en 7 tokens de catcode 12\idx*{catcode!12 (autre)} qui sont \boxtoken{ \unskip\textbackslash} \boxtoken{f} \boxtoken{o} \boxtoken{o} \boxtoken{b} \boxtoken{a} \boxtoken{r}. Il suffit de manger le premier token \boxtoken{ \unskip\textbackslash} avec un \xA7\gobone en ayant pris soin de 1-d\xE9velopper \idx\string avant que \xA7\gobone n'entre en action :
+
+\centrecode-\def\newunivar#1{%\xA4\xA7*\newunivar\xA4
+	\def#1[##1]{\csname\expandafter\gobone\string#1@##1\endcsname}}\xA4\idx*\string\xA7*\gobone\xA4
+\def\defunivar#1[#2]{%\xA4\xA7*\defunivar\xA4
+	\defname{\expandafter\gobone\string#1@#2}}\xA4\idx*\string\xA7*\gobone\xA7*\defname\xA4-
+\end{exercice}
+
+\begin{center}
+$\star$\par
+$\star\quad\star$
+\end{center}
+
+Voici la fin de cette longue et difficile partie o\xF9, en nous int\xE9ressant aux commandes, nous avons d\xE9couvert comment \TeX{} fonctionne. Pour r\xE9sumer \xE0 l'extr\xEAme, \TeX{} est un langage de macros et donc, se comporte comme une machine qui remplace du code par du code jusqu'\xE0 arriver \xE0 des tokens non d\xE9veloppables qui seront \xABex\xE9cut\xE9s\xBB (des primitives, des caract\xE8res ordinaires de catcode 10, 11 ou 12 qui seront affich\xE9s ou des caract\xE8res rev\xEAtant des propri\xE9t\xE9s li\xE9es \xE0 leur catcode, comme \verb|$|).
+
+Si l'on entre un peu plus dans les d\xE9tails et en r\xE9sumant ce qui a \xE9t\xE9 dit, voici comment on peut se repr\xE9senter le fonctionnement de \TeX{} : comme nous l'avons vu \xE0 la premi\xE8re partie, le code \TeX{} est constitu\xE9 de cases chacune form\xE9e d'un \idx{octet} pour les \idx*{moteur!8 bits}moteurs 8 bits ou par une s\xE9quence d'octets codant un caract\xE8re \utf pour les moteurs \utf.\idx*{moteur!utf8} Lorsqu'ils sont transform\xE9s en tokens lorsque \TeX{} les lit, chacun de ces caract\xE8res ob\xE9it \xE0 des r\xE8gles particuli\xE8res propres \xE0 leurs cat\xE9gories. Voici les cas particuliers qui sont transform\xE9s lors de la lecture :
+
+\begin{itemize}
+	\item lorsque des lettres sont pr\xE9c\xE9d\xE9es du \idx{caract\xE8re d'\xE9chappement} \xAB\verb-\-\xBB de catcode 0\idx*{catcode!0 (caract\xE8re d'\xE9chappement)}, le tout ne forme qu'un seul token, une \idx{s\xE9quence de contr\xF4le};
+	\item lorsqu'un \idx{espace} (catcode \number\catcode`\ )\idx*{catcode!10 (espace)} dans le code est suivi d'autres espaces\idx*{espace!cons\xE9cutifs}, les autres espaces sont ignor\xE9s;
+	\item un seul retour charriot \verbidx[ (retour charriot)]{^^M} (catcode 5) est compris comme \xE9tant un espace;
+	\item deux retours charriots cons\xE9cutifs sont \xE9quivalents au token \idx\par;
+	\item deux caract\xE8res identiques de catcode \number\catcode`\^\idx*{catcode!7 (exposant)} cons\xE9cutifs (comme \xAB\verbidx{^^}\xBB) sont convertis en un caract\xE8re selon les r\xE8gles expos\xE9es \xE0 la 1\iere{} partie;
+	\item le caract\xE8re \xAB\cidx\%\xBB (catcode \number\catcode`\%) ainsi que tous les caract\xE8res jusqu'au retour charriot suivant sont ignor\xE9s.
+\end{itemize}
+
+Ainsi, on peut consid\xE9rer le code \TeX{} comme \xE9tant des caract\xE8res \xE9crits les uns \xE0 la suite des autres comme s'ils \xE9taient sur un ruban et, apr\xE8s leur lecture, ces caract\xE8res sont transform\xE9s en de la mati\xE8re assimilable par \TeX{}, les tokens. \TeX{} fonctionne \xE0 la mani\xE8re d'une t\xEAte de lecture qui se d\xE9place toujours lin\xE9airement de gauche \xE0 droite sur le ruban o\xF9 est \xE9crit le code. Voici, comment on peut se repr\xE9senter sch\xE9matiquement le fonctionnement de \TeX{} :
+
+\begin{enumerate}
+	\item lire un token : utiliser en priorit\xE9 les tokens stock\xE9s dans la pile d'entr\xE9e si elle n'est pas vide et dans le cas contraire, construire le token \xE0 partir des caract\xE8res du code source en appliquant les r\xE8gles de lecture du code en vigueur \xE0 ce moment-l\xE0.
+	
+	Si ce token lu requiert la lecture d'autres tokens (lecture d'un nombre, cas d'une macro \xE0 plusieurs arguments, cas de \verb|\def| qui doit \xEAtre suivi d'une macro, d'un texte de param\xE8tre et d'un texte de remplacement, etc.), recommencer en 1 jusqu'\xE0 ce que les tokens requis soient lus;
+	\item figer les catcodes de tous les tokens lus et les stocker en m\xE9moire;
+	\begin{enumerate}
+	\item si ce qui vient d'\xEAtre lu n'est pas d\xE9veloppable, ex\xE9cuter l'action que commande le tout;
+	\item sinon, 1-d\xE9velopper le premier token et ins\xE9rer devant la t\xEAte de lecture (dans la \idx{pile d'entr\xE9e}) ce qui en r\xE9sulte;
+	\end{enumerate}
+	\item retourner en 1.
+\end{enumerate}
+
+Lorsque \TeX{} est en phase de d\xE9veloppement et si \verb|\expandfter| est la primitive \xE0 d\xE9velopper, convenons que 0 est la position de cet \verb|\expandafter| dans la liste des tokens \xE0 lire. Lorsque \verb|\expandafter| est d\xE9velopp\xE9, la t\xEAte de lecture de \TeX{} a la capacit\xE9, sans bouger de place, de \xABd\xE9tacher\xBB une \xABt\xEAte de d\xE9veloppement\xBB. Celle-ci, en se d\xE9solidarisant de la t\xEAte de lecture, ira 1-d\xE9velopper le token se trouvant plus loin dans le code \xE0 la position 2 et suivra \xE9ventuellement les ordres de d\xE9veloppement que son 1-d\xE9veloppement implique. Une fois qu'il n'y a plus d'ordre de d\xE9veloppement \xE0 suivre, la t\xEAte de d\xE9veloppement revient sur la t\xEAte de lecture qui reprend son travail o\xF9 elle l'avait laiss\xE9 et tiendra compte, dans le futur, des d\xE9veloppements effectu\xE9s par sa t\xEAte de d\xE9veloppement.
+\grandsaut
+
+On peut donc \xE9noncer que le fonctionnement de \TeX{} s'apparente \xE0 celui d'une \xAB\idx*{Turing (machine)}machine de Turing\xBB.\idx*[|)]{d\xE9veloppement}
+%|                                                                            |
+%|                                Fin partie 2                                |
+%|____________________________________________________________________________|
+
+% ____________________________________________________________________________
+%|                                                                            |
+%|                                  Partie 3                                  |
+%|                                                                            |
+\defpartcomment{\lettrine[lines=3,slope=4pt,nindent=0pt]{\libertineInitialGlyph{A}}{\kern -5pt pr\xE8s} avoir abord\xE9 la plus grosse partie des sp\xE9cificit\xE9s de \TeX{}, nous pouvons entrer dans le vif du sujet avec de la programmation non lin\xE9aire. Aucun algorithme complexe ne sera abord\xE9 dans cette partie, bien au contraire, nous nous en tiendrons aux plus \xE9l\xE9mentaires et aux plus passepartouts. Malgr\xE9 leur simplicit\xE9, ils sont n\xE9anmoins difficiles \xE0 cause des sp\xE9cificit\xE9s du langage \TeX{}.}
+
+\part{Structures de contr\xF4le et r\xE9cursivit\xE9}
+\chapter{Les outils de programmation de \TeX}
+Le langage \TeX{} a \xE9t\xE9 dot\xE9 des structures de contr\xF4les n\xE9cessaires pour \xE9laborer n'importe quel algorithme, aussi compliqu\xE9 soit-il. \xC0 ce titre, c'est donc un langage \emph{complet}\idx*{langage complet}. Bien s\xFBr, il ne viendrait \xE0 l'id\xE9e de personne de coder en \TeX{} un d\xE9compresseur zip ou un algorithme de jeu d'\xE9checs\footnote{Il faut tout de m\xEAme signaler une r\xE9cente extension appel\xE9e \xAB reverxii \xBB pour \TeX{} qui joue au jeu d'Othello et qui tient en moins de 1000 octets ! Cette tr\xE8s faible taille tient au fait que l'auteur a utilis\xE9 toutes les astuces \TeX{}iennes (programmation de caract\xE8res actifs notamment) pour que la taille soit la plus petite possible, au prix d'une lisibilit\xE9 nulle \xE0 un tel point qu'il est presque impossible de dire s'il s'agit de code \TeX{} ou pas !\par Le programme comporte une intelligence artificielle qui, bien que loin d'\xEAtre redoutable, peut tenir t\xEAte \xE0 un joueur d\xE9butant.} ! Dans le monde de \TeX{}, le mot \xAB compilation \xBB signifie \xAB traduction de la totalit\xE9 code source en document affichable \xBB. En \TeX{}, lorsqu'on parle de programmation, ce mot devient ambigu, car dans le monde de la programmation, \xAB compilation\xBB signifie \xAB transformation du code source en code ex\xE9cutable \xBB, le fichier binaire ex\xE9cutable obtenu \xE9tant d'une grande rapidit\xE9. Ce qu'il faut comprendre est que le langage \TeX{} est \emph{interpr\xE9t\xE9}, c'est-\xE0-dire \xAB ex\xE9cut\xE9 au fur et \xE0 mesure \xBB lors de la compilation ce qui le rend lent !
+\grandsaut
+
+Les principales structures de contr\xF4le dont \TeX{} est dot\xE9 sont les suivantes :
+
+\begin{itemize}
+	\item l'assignation, c'est-\xE0-dire la possibilit\xE9 de stocker des informations dans des \xAB registres \xBB (le mot \xAB variables \xBB est plus couramment utilis\xE9 dans d'autres langages), qui sont en quelque sorte des endroits de la m\xE9moire accessibles et lisibles facilement. En \TeX{}, les structures les plus couramment utilis\xE9es capables de stocker de l'information sont les suivants :
+	\begin{itemize}
+		\item les s\xE9quences de contr\xF4le;
+		\item les registres de tokens;
+		\item les registres d'entiers ou \xAB compteurs \xBB qui accueillent les entiers et sont dot\xE9s des 4 op\xE9rations o\xF9 la division n'est possible que par un entier, \xE9tant entendu que cette division donne la partie enti\xE8re;
+		\item les registres de dimensions stockent des longueurs et qui permettent, sous certaines r\xE9serves que nous verrons, de manipuler des nombres d\xE9cimaux. Les 4 op\xE9rations sont disponibles, mais la division n'est possible que par un \emph{entier};
+		\item les registres de boites qui stockent un contenu arbitraire sous forme affichable, mais il n'est plus possible d'acc\xE9der au code qui a g\xE9n\xE9r\xE9 ce contenu.
+	\end{itemize}
+	\item les tests ;
+	\item la \idx{r\xE9cursivit\xE9}, c'est-\xE0-dire la possibilit\xE9 pour une macro de s'appeler elle-m\xEAme, que ce soit directement ou par l'interm\xE9diaire d'une ou plusieurs autres macros ;
+	\item la localit\xE9, c'est-\xE0-dire la possibilit\xE9 de d\xE9finir une zone o\xF9 les assignations resteront valables dans cette zone pour \xEAtre d\xE9truites une fois sorti de cette zone, tout en permettant de proc\xE9der \xE0 des assignations \emph{globales} qui survivent une fois que la zone est ferm\xE9e ;
+	\item la possibilit\xE9 d'\xE9crire dans un fichier, c'est-\xE0-dire d'y stocker des \emph{caract\xE8res};
+	\item la possibilit\xE9 de lire les caract\xE8res stock\xE9s dans un fichier.
+\end{itemize}
+
+Et c'est \xE0 peu pr\xE8s tout ! Cette liste est \emph{minimaliste} et n'a rien \xE0 voir le pl\xE9thore de moyens que propose un langage de programmation actuel. Pour faire une comparaison dans les moyens simples et basiques, il n'y a par exemple, aucune structure de boucle (for, loop, while, etc.). Ni de \xAB variables \xBB de type \xE9volu\xE9 comme les tableaux \xE0 plusieurs dimensions par exemple. Aucune trace non plus d'op\xE9rations scientifiques. Mais qu'\xE0 cela ne tienne, les structures \xE9nonc\xE9es ci-dessus sont bien suffisantes pour en programmer soi-m\xEAme. Il faut s'y habituer, en \TeX{}, on ne dispose que du strict minimum et bien souvent, on doit construire soi-m\xEAme des structures de contr\xF4le plus \xE9volu\xE9es comme les boucles. La plupart du temps avec \TeX, tout est question d'assignations, de lecture raisonn\xE9e d'arguments, de comparaison, de d\xE9veloppement et de r\xE9cursivit\xE9. Pour autant que \xE7a soit p\xE9nible au d\xE9but, en contrepartie, c'est extr\xEAmement souple puisqu'on peut b\xE2tir des boucles sur mesure. C'est ce que nous allons apprendre \xE0 faire dans cette partie en \xE9tudiant plus sp\xE9cialement les tests et la r\xE9cursivit\xE9.
+
+Mais avant de les aborder, il nous faut revenir aux nombres entiers et comprendre comment \TeX{} calcule.
+
+\chapter{\TeX{} et les entiers}\idx*[|(]{nombre}%
+S'il y a bien un domaine o\xF9 \TeX{} n'excelle pas, c'est celui du calcul. On ne pourrait lui en vouloir puisque, con\xE7u pour composer du texte, il n'\xE9tait pas n\xE9cessaire de le doter de puissants outils de calcul. Mais depuis que \TeX{} a \xE9t\xE9 \xE9crit, beaucoup de temps s'est \xE9coul\xE9 \xE0 l'\xE9chelle informatique et d\xE9sormais, tout langage embarque pl\xE9thore d'outils de calcul. Par cons\xE9quent, un programmeur habitu\xE9 \xE0 ces outils ressent \xE0 un moment ou \xE0 un autre une l\xE9gitime frustration envers \TeX{} qui ne les propose pas. Voyons tout de m\xEAme ce que \TeX{} offre en mati\xE8re de calculs arithm\xE9tiques.
+
+\section{L'arithm\xE9tique \TeX{}ienne}
+\subsection{Les entiers}
+\idx*[|(]{compteur}\TeX{} manipule des entiers sign\xE9s sur $32$ bits. Ils sont donc compris entre $-2^{31}+1$ et $2^{31}-1$ c'est-\xE0-dire entre $-\numprint{2147483647}$ et $\numprint{2147483647}$. Ces entiers sont stock\xE9s dans des registres sp\xE9ciaux appel\xE9s \xAB compteurs \xBB. 256 de ces registres sont disponibles avec \TeX{} et $\numprint{65536}$ avec $\varepsilon$\TeX{}. Ainsi, \verb|\count42| fait r\xE9f\xE9rence au compteur \no42. Contrairement aux registres de tokens avec \idx\toks\verb|0|, aucune convention n'existe quant \xE0 un compteur portant un num\xE9ro sp\xE9cial qui serait non utilis\xE9 et qui servirait de \xAB compteur brouillon \xBB.
+
+\TeX{} met aussi \xE0 disposition la primitive \idx\countdef, qui ressemble \xE0 \idx\chardef ou \idx\toksdef. Par exemple, \xE9crire
+
+\centrecode-\countdef\foo=42-\idx*\countdef
+
+\noindent rend \verb|\foo| \xE9quivalent \xE0 \verb|\count42| de telle sorte que le registre \no42 peut \xEAtre d\xE9sign\xE9 par la \idx{s\xE9quence de contr\xF4le} \verb|\foo|. L'\xE9quivalence dont il est question ici ressemble \xE0 celle de \idx\let en ce sens que \verb|\foo| n'est pas d\xE9veloppable et n'a pas de texte de remplacement mais \emph{sera} \verb|\count42|.
+
+Comme pour les registres de tokens avec \idx\toksdef, plain-\TeX{} fournit une macro \idx\newcount qui, suivie d'une \verb-\<macro>-, permet d'allouer un compteur pour y faire ensuite r\xE9f\xE9rence avec une macro plut\xF4t que par un num\xE9ro. La macro \idx\newcount se charge de trouver le num\xE9ro du prochain registre de compteur libre. Si par exemple, on \xE9crit \verb-\newcount\foo- et si 89 est le num\xE9ro du prochain registre libre, alors la macro \idx\newcount proc\xE8derait \xE0 l'assignation suivante :
+
+\centrecode-\global\countdef\foo=89-\idx*\global\idx*\countdef
+
+\noindent La primitive \idx\global, plac\xE9e devant l'assignation, rend celle-ci globale : on ne peut donc pas allouer localement un registre de compteur qui serait ensuite lib\xE9r\xE9 apr\xE8s la sortie d'un groupe\footnote{Bien \xE9videmment, mobiliser un compteur localement est possible, mais il faudrait \xE9crire une nouvelle macro le permettant. Ceci est fait par le \idx[!etex]{package} \texttt{etex.sty} pour \LaTeX{} qui, entre autres fonctionnalit\xE9s, fournit une macro \texttt{\char`\\loccount\char`\\\codeelement{macro}} par laquelle le compteur est d\xE9fini de fa\xE7on \emph{locale}.}.
+
+\begin{regle}
+Un compteur a vocation \xE0 contenir un nombre entier de $-2^{31}+1$ \xE0 $2^{31}-1$. On y fait r\xE9f\xE9rence par
+
+\centrecode-\count<nombre>-
+
+Il est aussi possible d'utiliser la commande
+
+\centrecode-\newcount\<macro>-
+
+qui fait le n\xE9cessaire pour lier la \verb|\<macro>| au prochain num\xE9ro de compteur non utilis\xE9. Par la suite, la \verb|\<macro>| se comporte exactement comme \idx\count\verb|<nombre>|. Comme les registres de tokens, les \verb|<compteurs>| peuvent donc indiff\xE9remment \xEAtre d\xE9sign\xE9s selon ces deux possibilit\xE9s.
+\grandsaut
+
+Pour assigner un \verb|<entier>| (voir la d\xE9finition d'un entier \xE0 la page~\pageref{definition.entier}) \xE0 un compteur, il faut \xE9crire\idx*{assignation!compteur}
+
+\centrecode-<compteur>= <entier>-
+
+\noindent o\xF9 le signe \verb-=- ainsi que l'espace qui le suit sont facultatifs.
+\end{regle}
+
+Rappelons que pour \emph{afficher} la valeur du compteur, nous ne pouvons pas \xE9crire \verb|<compteur>| dans le code sans risquer de provoquer une erreur de compilation. En effet, \TeX{} attendrait une assignation qui commence de cette fa\xE7on et si ce \verb|<compteur>| n'\xE9tait pas suivi d'un \verb|<nombre>|, \TeX{} se plaindrait d'un \xAB\texttt{Missing number, treated as zero} \xBB. Un compteur \xE9tant une repr\xE9sentation interne d'un entier, pour \emph{afficher} sa valeur, il faut traduire cette repr\xE9sentation interne en caract\xE8res affichables, et faire pr\xE9c\xE9der le \verb|<compteur>| de \idx\the, \idx\number ou \idx\romannumeral :
+
+\showcode/\newcount\foo \newcount\bar\xA4\idx*\newcount\xA4
+\foo=42 \bar=\foo \string\bar\ vaut : \the\bar \par\xA4\idx*\string\idx*\the\xA4
+\bar=\foo57 \string\bar\ vaut : \number\bar\par\xA4\defline\aaa\idx*\number\xA4
+\bar=2014 \string\bar\ vaut : \romannumeral\bar\xA4\idx*\romannumeral\idx*\string\xA4/
+
+\noindent La ligne \no\aaa{} montre que les caract\xE8res \xAB\verb|57|\xBB ne sont pas pris en compte pour l'affectation. Comme cela est dit \xE0 la page~\pageref{definition.entier}, si le \verb|<nombre>| que \TeX{} lit est un registre de compteur, le nombre qu'il contient est lu, et la lecture du nombre s'arr\xEAte (laissant ici \xAB\verb|57|\xBB hors du nombre pris en compte).
+
+\begin{exercice}
+\Qu e fait le code suivant ?
+
+\centrecode-\newcount\foo
+\newcount\bar
+\foo=57
+\bar=9\foo8\relax-
+
+\solution
+Tout d'abord, deux compteurs sont cr\xE9\xE9s. Le nombre \verb|57| est affect\xE9 au compteur \verb|\foo|. Puis, \xE0 la derni\xE8re ligne, \xE0 droite de \verb|\bar=|, l'entier lu est \verb|9| car la lecture du nombre s'arr\xEAte sur \verb|\foo| qui n'est pas d\xE9veloppable et n'est pas un chiffre.
+
+Le compteur \verb|\bar| vaut donc 9 et ce qui est \xE0 la suite \xAB\verb|\foo8\relax|\xBB est une affectation qui rendrait le compteur \verb|\foo| \xE9gal \xE0 8, \xE9crasant la valeur \verb|57| qu'il avait auparavant. Le code propos\xE9 fait 3 assignations et ne produit aucun affichage.
+
+\xC0 la derni\xE8re ligne, si nous avions voulu assigner 9578 au compteur \verb|\bar| (o\xF9 57 est la valeur du compteur \verb|\foo|), il aurait fallu \xE9crire  :
+
+\centrecode-\bar=9\number\foo8\relax-
+
+de telle sorte que le d\xE9veloppement mis en  place pour la lecture du nombre convertisse \idx\number\verb|\foo| en caract\xE8res valides pour un \verb|<nombre>|.
+\end{exercice}
+
+\subsection{Les op\xE9rations}\idx*[|(]{op\xE9rations arithm\xE9tiques}
+Venons-en aux op\xE9rations arithm\xE9tiques \xE0 notre disposition. Celles-ci op\xE8rent sur des compteurs, c'est-\xE0-dire qu'il n'est pas possible de faire des op\xE9rations sur des nombres explicitement \xE9crits en chiffres.
+
+\begin{regle}
+Dans les lignes ci-dessous, \verb|<n>| est un nombre entier au sens de \TeX{} :
+
+\begin{itemize}
+	\item \idx\advance\verb-<compteur> by <n>- : ajoute \verb-<n>- au \verb-<compteur>-;
+	\item \idx\multiply\verb-<compteur> by <n>-  : multiplie le \verb-<compteur>- par \verb-<n>-;
+	\item \idx\divide\verb-<compteur> by <n>- : divise le \verb-<compteur>- par \verb-<n>- en lui assignant la troncature \xE0 l'unit\xE9 si le r\xE9sultat de la division n'est pas entier.
+\end{itemize}
+
+Dans tous les cas, le mot \xAB\verb-by-\xBB et l'espace qui le suit sont facultatifs.
+\end{regle}
+
+Avec ces trois op\xE9rations, il est possible de programmer une macro \verb-\fonction- dont l'argument est un entier $n$ et qui calcule et affiche la valeur de $(3n-4)^2$. Le principe est d'assigner l'entier $n$ \xE0 un compteur et effectuer les op\xE9rations sur ce compteur (le multiplier par 3, lui ajouter $-4$, puis le multiplier par lui-m\xEAme) pour l'afficher ensuite :
+
+\showcode/\newcount\foo\xA4\idx*\newcount\xA4
+\def\fonction#1{%
+  \foo=#1 % assigne l'entier #1 au compteur puis
+  \multiply\foo3 % multiplie par 3\xA4\idx*\multiply\xA4
+  \advance\foo-4 % soustrait 4\xA4\idx*\advance\xA4
+  \multiply\foo\foo% \xE9l\xE8ve au carr\xE9 (lmultiplie \foo par lui m\xEAme)\xA4\idx*\multiply\xA4
+  \number\foo% enfin, afficher le r\xE9sultat\xA4\idx*\number\xA4
+}
+a) \fonction5\qquad b) \fonction{-13}/
+
+La macro donne bien les r\xE9sultats attendus, mais l'inconv\xE9nient est qu'elle n\xE9cessite un compteur et surtout qu'elle n'est pas purement d\xE9veloppable. En effet, si nous \xE9crivons \verb-\edef\bar{\fonction5}-, la macro \verb-\bar- n'aura pas 121 comme texte de remplacement. La raison est que le texte de remplacement de \verb-\fonction- contient des primitives qui ne se d\xE9veloppent pas (\idx\multiply, \idx\advance) et la s\xE9quence de contr\xF4le \verb|\foo| qui n'est pas d\xE9veloppable non plus. Il s'agit ici d'un cas qui illustre la fondamentale diff\xE9rence entre \xAB affichage produit par une macro apr\xE8s ex\xE9cution \xBB et \xAB texte de remplacement de cette macro \xBB. Ce n'est pas parce que \xAB\verb|\fonction5|\xBB affiche \verb|121| que tout se passe comme si \xAB\verb|\fonction5|\xBB \xE9tait \xE9quivalent (m\xEAme apr\xE8s d\xE9veloppement) aux caract\xE8res \verb|121|. Nous pouvons le constater sur cet exemple :
+
+\showcode/\newcount\foo\xA4\idx*\newcount\xA4
+\def\fonction#1{%
+  \foo=#1 \multiply\foo3 \advance\foo-4 \multiply\foo\foo\xA4\defline\aaa\idx*\multiply\idx*\advance\xA4
+  \number\foo}\xA4\idx*\number\xA4
+\edef\bar{\fonction{5}}%
+a) Signification : \meaning\bar\par\xA4\idx*\meaning\xA4
+b) Ex\xE9cution : \bar\xA4\defline\bbb\xA4/
+
+Pourquoi obtenons-nous \verb|0| lorsque \verb|\bar| est ex\xE9cut\xE9e ? Parce que le code contenu dans \verb|\bar| (et affich\xE9 au cas a) effectue dans un premier temps les calculs sur le compteur \verb|\foo|, mais au lieu d'afficher le ce que contient ce compteur, elle affiche 0, qui est le r\xE9sidu du d\xE9veloppement de \idx\number\verb|\foo|.
+\grandsaut
+
+Non contente de cr\xE9er une macro non purement d\xE9veloppable, la m\xE9thode pr\xE9c\xE9dente peut rapidement rendre l'enchainement des op\xE9rations lourd, fastidieux et peu lisible, pour peu que les expressions \xE0 calculer soient plus complexes. En l'\xE9tat de \TeX{} tel qu'il a \xE9t\xE9 \xE9crit par \idx*{Knuth Donald}D.~\textsc{Knuth}, il n'est pas possible de s'y prendre autrement. Heureusement, avec le moteur \idx\eTeX\idx*{moteur!etex}, une autre alternative est possible.
+
+\subsection{La primitive \texttt{\char`\\numexpr}}\idx*[|(]{\numexpr}
+Pour les entiers, la primitive \idx\numexpr\label{numexpr} permet d'effectuer un enchainement d'op\xE9rations arithm\xE9tiques via une \xE9criture math\xE9matique en notation infix\xE9e o\xF9 les priorit\xE9s arithm\xE9tiques habituelles sont respect\xE9es. Dans ces expressions, les espaces sont ignor\xE9s, les signes d'op\xE9rations sont \verb|+|, \verb|-|, \verb|*| et \verb|/| et des entiers explicitement \xE9crits en chiffres peuvent y figurer. Pour la division, la seule diff\xE9rence avec la division \TeX ienne r\xE9side dans le fait qu'elle donne \emph{l'entier le plus proche} au lieu de \emph{la troncature}\idx*{op\xE9rations arithm\xE9tiques!troncature (division)}. Les expressions aussi contenir des parenth\xE8ses.
+
+\begin{regle}
+La primitive \idx\numexpr permet de calculer des enchainements d'op\xE9rations sur les entiers, pris au sens de la d\xE9finition de la page~\pageref{definition.entier}. Elle doit \xEAtre suivie d'une expression arithm\xE9tique o\xF9 les espaces sont ignor\xE9s, les signes op\xE9ratoires sont \verb|+|, \verb|-|, \verb|*|, \verb|/| et o\xF9 les parenth\xE8ses sont admises .
+
+Elle cherche \xE0 \xE9valuer ce qui la suit en amor\xE7ant un d\xE9veloppement maximal jusqu'\xE0 rencontrer un token qui ne peut figurer dans une expression arithm\xE9tique. Si l'expression arithm\xE9tique est suivie d'un \idx\relax, alors ce \idx\relax est mang\xE9 par \idx\numexpr. Ceci constitue une sp\xE9cificit\xE9 de la primitive \texttt{\string\numexpr} puisqu'avec \TeX, seuls les \emph{espaces} sont mang\xE9s apr\xE8s les nombres. C'est donc une excellente habitude de faire suivre une expression arithm\xE9tique \xE9valu\xE9e par \idx\numexpr d'un \idx\relax.
+
+La structure
+
+\centrecode-\numexpr<expression arithm\xE9tique>\relax>-
+
+est un entier au sens de \TeX{}, mais un peu comme l'est un compteur, c'est une repr\xE9sentation \emph{interne} d'un entier et donc, pour l'afficher, il faut recourir \xE0 une primitive qui transforme la repr\xE9sentation interne en caract\xE8res affichables telle que \idx\the, \idx\number ou \idx\romannumeral.
+\end{regle}
+
+L'exemple suivant montre comment, avec \idx\number, on peut afficher une expression \xE9valu\xE9e par \idx\numexpr :
+
+\showcode|a) \number\numexpr2+3*4\relax\qquad\xA4\idx*\number\idx*\numexpr\xA4
+b) \romannumeral\numexpr2*3\relax\qquad\xA4\idx*\romannumeral\xA4
+c) \number\numexpr(6-2*4)*(1-(2-6))\relax\qquad
+d) \number\numexpr7/4\relax\qquad %7/4 vaut 1,75
+e) \edef\foo{\number\numexpr2+3*4\relax}\meaning\foo\xA4\idx*\meaning\xA4|
+
+Une expression \xE9valu\xE9e par \idx\numexpr peut contenir une sous-expression, elle-m\xEAme \xE9valu\xE9e par un autre \idx\numexpr. Voici comment calculer 3*(1+2*5)+2, en \xE9valuant l'expression entre parenth\xE8ses avec un \idx\numexpr imbriqu\xE9 dans l'expression \xE0 calculer et en prenant soin de stopper sa port\xE9e par un \idx\relax :
+
+\showcode/\number\numexpr3*\numexpr1+2*5\relax+2\relax/
+
+L'emploi de \idx\numexpr peut rendre la macro \verb-\fonction- vue pr\xE9c\xE9demment \emph{purement d\xE9veloppable} :
+
+\showcode/\def\fonction#1{\number\numexpr(3*#1-4)*(3*#1-4)\relax}\xA4\idx*\number\idx*\numexpr\xA4
+a) \fonction5\qquad
+b) \fonction{-13}\qquad
+c) \edef\bar{\fonction5}\meaning\bar\xA4\idx*\meaning\xA4/
+
+\begin{exercice}
+Dans le code ci-dessus, l'expression \xAB\verb|3*#1-4|\xBB est \xE9valu\xE9e \emph{deux} fois, ce qui est inutile et consommateur de temps. Comment modifier le code pour qu'elle ne soit \xE9valu\xE9e qu'une seule fois ?
+\solution
+L'id\xE9e est de provoquer le calcul de \xAB\verb|3*#1-4|\xBB et passer le r\xE9sultat \xE0 une macro auxiliaire \verb|\carre| qui affichera le carr\xE9 de son argument:
+
+\showcode/\def\fonction#1{\exparg\carre{\number\numexpr3*#1-4\relax}}\xA4\idx*\numexpr\xA7*\exparg\xA4
+\def\carre#1{\number\numexpr#1*#1\relax}\xA4\idx*\number\idx*\numexpr\xA4
+a) \fonction{5}\qquad
+b) \fonction{-13}\qquad
+c) \edef\bar{\fonction5}\meaning\bar\xA4\idx*\meaning\xA4/
+
+Ici, la macro \xA7\exparg 1-d\xE9veloppe et force le calcul de \verb|\number\numexpr3*#1-4\relax| en un nombre sign\xE9 explicitement \xE9crit, qui est transmis \xE0 la macro \verb|\carre| qui se charge de le multiplier par lui-m\xEAme.
+\end{exercice}
+
+Il est parfois g\xEAnant que la primitive de \TeX{} \idx\divide sur les compteurs et la division \xAB\verb|/|\xBB de \idx\numexpr ne donnent pas les m\xEAmes r\xE9sultats. En effet, cela rompt la coh\xE9rence qui existe entre les trois autres op\xE9rations. Comment r\xE9concilier les deux et faire en sorte d'inventer une division pour \idx\eTeX{} qui donne aussi la troncature ? Pour cela, il existe une formule g\xE9n\xE9rale. Si $x$ et $y$ sont deux entiers \emph{positifs}, si \xAB\verb|/|\xBB repr\xE9sente la division donnant l'entier le plus proche (la division de \idx\numexpr donc), la troncature du quotient de $x$ par $y$ est
+
+\[(x-(y-1)/2)/y\]
+
+\xC0 l'aide de \idx\numexpr, il est facile de programmer une macro \verb|\truncdiv{|$x$\verb|}{|$y$\verb|}| qui calcule la troncature du quotient de $x$ par $y$. Le r\xE9sultat est donn\xE9 sous la forme d'un entier \emph{non explicite}, c'est-\xE0-dire qu'il faut \idx\number pour transformer cet entier en nombre affichable :
+
+\showcode|\def\truncdiv#1#2{\numexpr(#1-(#2-1)/2)/#2\relax}\xA4\idx*\numexpr\xA7*\truncdiv\idx*\number\xA4
+8/3 :
+a) \number\truncdiv83\qquad      % doit donner 2
+b) \number\truncdiv{-8}3\qquad   % doit donner -2
+c) \number\truncdiv8{-3}\qquad   % doit donner -2
+d) \number\truncdiv{-8}{-3}\par  % doit donner 2
+4/3 :
+e) \number\truncdiv43\qquad      % doit donner 1
+f) \number\truncdiv{-4}3\qquad   % doit donner -1
+g) \number\truncdiv4{-3}\qquad   % doit donner -1
+h) \number\truncdiv{-4}{-3}      % doit donner 1\xA4\xA7*\truncdiv\xA4|
+
+La macro donne bien des r\xE9sultats erron\xE9s lorsque les nombres sont de signes contraires. Nous verrons au prochain chapitre comment la modifier pour que le r\xE9sultat soit correct dans tous les cas.
+
+Bien entendu, \xA7\truncdiv peut \xEAtre \xE9crite dans une expression num\xE9rique \xE9valu\xE9e par \idx\numexpr puisque les \idx\numexpr peuvent \xEAtre imbriqu\xE9s sous r\xE9serve que les \idx\numexpr internes aient leur port\xE9e limit\xE9e par \idx\relax, ce qui est le cas ici.\idx*[|)]{op\xE9rations arithm\xE9tiques}\idx*[|)]{\numexpr}
+
+\section{Le test \texttt{\textbackslash{}ifnum}}\label{ifnum}\tidx*[|(]{ifnum}%
+Le test \tidx{ifnum} est le premier test abord\xE9 puisqu'il a un \xE9troit rapport avec le chapitre en cours sur les nombres entiers. Il est aussi l'un des plus fr\xE9quents.  Il n'est cependant qu'un test parmi beaucoup d'autres et avant de s'int\xE9resser plus en d\xE9tail \xE0 \tidx{ifnum}, un peu de th\xE9orie sur les tests de \TeX{} doit \xEAtre abord\xE9e.
+
+\subsection{Structure des tests}
+
+\begin{regle}
+Les tests de \TeX{} sont ex\xE9cut\xE9s par des primitives qui ob\xE9issent aux contraintes suivantes :
+
+\begin{enumerate}
+	\item le nom des primitives ex\xE9cutant un test commence par les lettres \xAB\verb|if|\xBB suivies d'autres lettres not\xE9es \verb|<test>| d\xE9terminant de quel test il s'agit;
+	\item si \verb|\if<test>| est une primitive ex\xE9cutant un test sur ses \verb|<arguments>|, sa structure est la suivante :
+
+\centrecode-\if<test><arguments>
+	<code ex\xE9cut\xE9 si le test est vrai>
+\else
+	<code ex\xE9cut\xE9 si le test est faux>
+\fi-
+
+	La branche entre \tidx{else} et \tidx{fi} est facultative et donc, un test peut \xE9galement avoir la structure suivante :
+
+\centrecode-\if<test><arguments>
+	<code ex\xE9cut\xE9 si le test est vrai>
+\fi-
+\end{enumerate}
+
+Au lieu de \tidx{else} et \tidx{fi}, on peut mettre toute s\xE9quence de contr\xF4le rendue \idx\let-\xE9gale \xE0 \tidx{else} ou \tidx{fi}.
+
+Les tests et les primitives \tidx{else} et \tidx{fi} sont d\xE9veloppables.
+\end{regle}
+
+Les codes ex\xE9cut\xE9s selon l'issue du test peuvent aussi contenir des tests sans que \TeX{} ne s'y perde dans les appariements entre les primitives \verb|\if<test>| et leur \tidx{else} ou \tidx{fi}. En effet, un peu comme le compteur d'accolades, \TeX{} est dot\xE9 d'un compteur interne d'imbrication de tests qui assure que chaque primitive de test est correctement appari\xE9e avec le bon \tidx{else} ou \tidx{fi}.
+
+Il est en outre primordial de comprendre qu'\xE0 l'occasion d'un test, la t\xEAte de lecture de \TeX{} \emph{ne lit pas} tout le code d\xE9pendant du test (jusqu'au \tidx{fi}) pour stocker en m\xE9moire les codes \xE0 ex\xE9cuter selon l'issue du test afin de mettre l'un ou l'autre sur la pile juste apr\xE8s avoir effectu\xE9 le test. Non, apr\xE8s avoir ex\xE9cut\xE9 le test elle continue sa lecture lin\xE9aire, mais elle \emph{sait} qu'elle se trouve dans la port\xE9e d'un test et qu'\xE0 un moment ou \xE0 un autre, elle aura \xE0 lire \tidx{fi}, \xE9ventuellement pr\xE9c\xE9d\xE9 d'un \tidx{else}.
+
+Pour que ce point soit clair, mettons-nous \xE0 la place de la t\xEAte de lecture de \TeX{} qui doit ex\xE9cuter le test suivant (cas \no1) :
+
+\centrecode-\if<test><arguments><code vrai>\else <code faux>\fi-
+
+\noindent ou (cas \no2) :
+
+\centrecode-\if<test><arguments><code vrai>\fi-
+
+\subsubsection{Test vrai}
+Supposons pour l'instant que le test est vrai. Voici l'enchainement des op\xE9rations qui vont avoir lieu :
+
+\begin{enumerate}
+	\item tout va commencer par le 1-d\xE9veloppement de \xAB\verb|\if<test><arguments>|\xBB qui va disparaitre \xE0 l'occasion de ce d\xE9veloppement;
+	\item ce qui est \xE0 suivre, le \verb|<code vrai>| est ex\xE9cut\xE9 normalement;
+	\item le 1-d\xE9veloppement de qui suit est vide. Il s'agit de 
+	\begin{centrage}\small
+		\verb|\else <code faux>\fi|\quad(cas \no1)\kern1cm ou\kern1cm \verb|\fi|\quad(cas \no2)
+	\end{centrage}
+\end{enumerate}
+
+\subsubsection{Test faux}
+Supposons \xE0 pr\xE9sent que le test est faux. Voici ce qui va se passer :
+
+\begin{itemize}
+	\item cas \no1 : 
+	\begin{enumerate}
+		\item le 1-d\xE9veloppement de \xAB\verb-\if<test><arguments><code vrai>\else-\xBB\linebreak[4] est vide (o\xF9 le \tidx{else} est appari\xE9 avec le test initial);
+	\item ce qui suit, c'est-\xE0-dire \verb|<code faux>| est ex\xE9cut\xE9 normalement;
+	\item le \tidx{fi} final qui reste est 1-d\xE9velopp\xE9 et disparait.
+	\end{enumerate}
+	\item cas \no 2 : le 1-d\xE9veloppement de \xAB\verb-\if<test><arguments><code vrai>\fi-\xBB est vide et la totalit\xE9 de ce code disparait donc en 1-d\xE9veloppement.
+\end{itemize}
+
+\begin{regle}
+Lorsqu'un test est ex\xE9cut\xE9 par une primitive de test \verb|\if<test>|, les primitives \tidx{else} et \tidx{fi} ne sont \emph{pas} supprim\xE9es lorsque le test est fait. Elles restent en place et lorsqu'elles seront rencontr\xE9es plus tard, elles s'autod\xE9truiront par un simple d\xE9veloppement.
+\end{regle}
+
+\subsection{Comparer des entiers}
+\subsubsection{Le test \texttt{\char`\\ifnum}}
+\begin{regle}
+La primitive \tidx{ifnum}  effectue une comparaison entre deux entiers. La syntaxe est de la forme
+
+\centrecode-\ifnum<entier1><signe><entier2>
+	<code ex\xE9cut\xE9 si le test est vrai>
+\else
+	<code ex\xE9cut\xE9 si le test est faux>
+\fi-
+
+\noindent o\xF9 le \verb-<signe>-, de catcode 12\idx*{catcode!12 (autre)}, est soit \xAB\verb-=-\xBB si l'on veut tester l'\xE9galit\xE9 entre les deux entiers, soit \xAB\verb-<-\xBB ou \xAB\verb->-\xBB s'il l'on cherche \xE0 tester une in\xE9galit\xE9 stricte.
+\end{regle}
+
+\showcode/a) \ifnum 15=14 vrai\else faux\fi\qquad% test faux\xA4\tidx*{ifnum}\xA4
+b) \ifnum4<200 vrai\else faux\fi\qquad% test vrai
+c) \newcount\foo \foo=9
+   \ifnum\foo>9 nombre\else chiffre\fi% test faux\xA4\idx*\newcount\xA4/
+
+V\xE9rifions maintenant ce qui a \xE9t\xE9 expos\xE9 en th\xE9orie sur le 1-d\xE9veloppement d'un test. Pour ce faire, mettons \xE0 contribution la macro \verb|\>...<| vue \xE0 la partie pr\xE9c\xE9dente :
+
+\showcode/\long\def\>#1<{\detokenize{#1}}\xA4\idx*\long\idx*\detokenize\xA4
+\expandafter\>\ifnum5=5 vrai\else faux\fi<\par% test vrai
+\expandafter\>\ifnum5=6 vrai\else faux\fi<% test faux
+\fi\fi% r\xE9tablir l'\xE9quilibre \ifnum et \fi\xA4\defline\aaa\xA4/
+
+Les trois premi\xE8res lignes de ce code permettent de visualiser les choses, mais rompent l'\xE9quilibre entre les \tidx{ifnum} et les \tidx{fi}. En effet, les \tidx{ifnum} sont ex\xE9cut\xE9s par \verb|\expandafter|, mais les \tidx{fi}, d\xE9tok\xE9nis\xE9s par \verb|\>|, ne seront jamais ex\xE9cut\xE9s par \TeX. Pour r\xE9tablir l'\xE9quilibre et \xE9viter que ce bug ne se propage jusqu'\xE0 la fin du code source de ce livre, deux \tidx{fi} ont \xE9t\xE9 rajout\xE9s \xE0 la ligne \no\aaa.
+
+\begin{exercice}
+V\xE9rifier que les appariements des tests avec leur \tidx{else} et \tidx{fi} sont corrects en programmant une macro \verb-\numtest- qui admet un argument de type entier et qui affiche \xABchiffre\xBB si son argument est compris entre $-9$ et $9$ inclus. Dans les autres cas, la macro doit afficher \xABnombre positif\xBB  ou \xABnombre n\xE9gatif\xBB.
+\solution
+Voici une fa\xE7on  de programmer la macro \verb|\numtest| qui, compte tenu de ce qui a \xE9t\xE9 dit sur le d\xE9veloppement des tests, est purement d\xE9veloppable :
+
+\showcode/\def\numtest#1{%
+	\ifnum#1>-10 \xA4\tidx*{ifnum}\xA4
+		\ifnum#1<10
+			chiffre%
+		\else
+			nombre positif%
+		\fi
+	\else
+		nombre n\xE9gatif%
+	\fi
+}
+a) \numtest{3}\qquad
+b) \numtest{-67}\qquad
+c) \numtest{-8}\qquad
+d) \numtest{21}\qquad
+e) \edef\foo{\numtest{2014}}\meaning\foo\xA4\idx*\meaning\xA4/
+\end{exercice}
+\begin{exercice}
+\xC9crire une macro \verb-\normalise- qui admet un argument de type entier positif. Si l'entier est compris entre 0 et 999 compris, cette macro devra afficher son argument avec 3 chiffres, quitte \xE0 rajouter des 0 inutiles \xE0 gauche pour satisfaire cette exigence. Dans les autres cas, aucun affichage ne sera fait.
+
+Par exemple, l'argument \xAB17\xBB donnera un affichage de \xAB017\xBB et \xAB8\xBB sera affich\xE9 \xAB008\xBB.
+\solution
+Il suffit d'imbriquer des tests comme \xE0 l'exemple pr\xE9c\xE9dent et afficher 00 ou 0 juste avant l'argument \verb-#1- selon le cas. Ici par contre, la branche \tidx{else} n'est pas n\xE9cessaire :
+
+\showcode/\def\normalise#1{%
+	\ifnum#1>-1 % ne faire quelque chose que si #1 est positif ou nul\xA4\tidx*{ifnum}\xA4
+		\ifnum#1<100 % si <100
+			0% afficher un 0
+			\ifnum#1<10 % si <10
+				0%afficher un autre 0
+			\fi
+		\fi
+		\number#1 %afficher le nombre\xA4\idx*\number\xA4
+	\fi}% affiche le nombre
+a) \normalise{749}\qquad
+b) \normalise{0017}\qquad
+c) \normalise8\qquad
+d) \normalise{1789}\qquad
+e) \normalise{-18}\qquad
+f) \normalise{0}/
+
+Le \idx\number qui se trouve devant l'entier \verb-#1- a deux fonctions :
+\begin{itemize}
+	\item celle d'afficher \verb-#1- sans provoquer d'erreur de compilation si \verb-#1- est un compteur;
+	\item purger les \xE9ventuels 0 inutiles qui se trouvent \xE0 gauche de \verb-#1- si celui-ci est \xE9crit explicitement. Ainsi, \xE9crire \verb-\normalise{0017}- m\xE8ne au r\xE9sultat correct.
+\end{itemize}
+
+Il reste \xE0 remarquer que la macro \verb|\normalise|, puisque son texte de remplacement n'est constitu\xE9 que de tests et de caract\xE8res affichables, est purement d\xE9veloppable.
+\end{exercice}
+
+\subsubsection{Le test \texttt{\char`\\ifcase}}\tidx*[|(]{ifcase}%
+Pour seconder le test \tidx{ifnum}, \TeX{} met \xE0 disposition le test \tidx{ifcase} qui op\xE8re \xE9galement sur des entiers. Ce test fait un peu chambre \xE0 part dans le monde des tests, car sa syntaxe \xE9chappe \xE0 la syntaxe g\xE9n\xE9rale des tests et c'est pourquoi elle est expliqu\xE9e en d\xE9tail ici.
+
+\tidx*[|(]{or}\begin{regle}
+Le test \tidx{ifcase} teste si un entier est successivement \xE9gal \xE0 0, 1, 2, ... selon la syntaxe suivante :
+
+\tidx{or}\centrecode-\ifcase<nombre>
+	<code ex\xE9cut\xE9> si <nombre> = 0
+\or
+	<code ex\xE9cut\xE9> si <nombre> = 1
+\or
+	<code ex\xE9cut\xE9> si <nombre> = 2
+etc...
+\else
+	<code alternatif>% ex\xE9cut\xE9 si aucune \xE9galit\xE9 pr\xE9c\xE9dente n'est v\xE9rifi\xE9e
+\fi-
+
+Les entiers auxquels le \verb|<nombre>| est compar\xE9 commencent n\xE9cessairement \xE0 0, sont cons\xE9cutifs et vont aussi loin qu'il y a de branches \tidx{or}. Il est donc n\xE9cessaire d'\xE9crire autant de \tidx{or} que l'on veut envisager de cas.
+
+La branche \verb|\else<code alternatif>| est facultative.
+\end{regle}
+
+Voici comment nous pourrions programmer une macro \verb|\mois{<entier>}| qui affiche en toutes lettres le nom du mois dont le num\xE9ro est pass\xE9 en argument. Il est m\xEAme possible de donner le mois en cours comme argument avec la primitive \idx\month, se comportant comme un compteur, qui contient le num\xE9ro du mois en cours :
+
+\showcode/\def\mois#1{%
+	\ifcase#1\relax\xA4\tidx*{ifcase}\xA4
+	    \char`\#\char`\#% afficher "##" si argument = 0
+	\or janvier\or f\'evrier\or mars\or avril%\xA4\tidx{or}\xA4
+	\or mai\or juin\or juillet\or aout%
+	\or septembre\or octobre\or novembre\or d\'ecembre%
+	\else
+	    \char`\#\char`\#% afficher "##" sinon
+	\fi
+}
+a) \mois{-4}\qquad
+b) \mois{3}\qquad
+c) \mois{11}\qquad
+d) \mois{20}\qquad
+e) \edef\foo{\mois{\month}}\meaning\foo% mois en cours\xA4\idx*\month\xA4/\tidx*[|)]{ifcase}\tidx*[|)]{or}%
+
+\subsection{Programmer un test : syntaxe}
+Les primitives de \TeX{} ne suffisent pas --~et de loin~-- \xE0 couvrir tous les tests qu'il est possible de faire. On est donc parfois amen\xE9 \xE0 programmer des \emph{macros} qui effectuent des tests plus complexes \xE0 l'aide notamment d'imbrications de tests primitifs. D\xE9cidons d\xE8s \xE0 pr\xE9sent que les noms de ces macros commencent aussi par les lettres \xAB\verb|if|\xBB suivies d'autres lettres not\xE9es \verb|<test>|. C'est un choix \emph{arbitraire} et tout autre choix aurait \xE9galement \xE9t\xE9 l\xE9gitime : certains font commencer les \emph{macros} de test par les lettres \emph{majuscules} \xAB\verb|IF|\xBB pour ne pas qu'elles soient confondues avec les \emph{primitive}s qui commencent avec des lettres \emph{minuscules}.
+
+La syntaxe de ces macros, diff\xE9rente de celle des primitives de test, fait davantage consensus. Si \verb|\if<test>| est une macro effectuant un test sur ses \verb|<arguments>| (pris comme argument d'une macro), il est extr\xEAmement courant d'adopter la syntaxe suivante, tr\xE8s facile d'utilisation :
+
+\centrecode-\if<test><arguments>
+	{<code ex\xE9cut\xE9 si le test est vrai>}
+	{<code ex\xE9cut\xE9 si le test est faux>}-
+
+Basons-nous sur cette syntaxe pour programmer une macro \xA7\ifletter[|(] qui teste si son argument, que l'on suppose constitu\xE9 d'un seul caract\xE8re, not\xE9 \verb|<car>|, est une lettre \emph{minuscule}. Par souci de concision, notons \verb|<code vrai>| et \verb|<code faux>| les codes ex\xE9cut\xE9s selon les issues des tests :
+
+\centrecode-\ifletter{<car>}
+	{<code vrai>}
+	{<code faux>}-
+
+Pour effectuer le test avec \tidx{ifnum}, seule primitive de test que nous connaissons pour l'instant, il va falloir exploiter une fa\xE7on d'\xE9crire un entier qui est \verb|`<car>| o\xF9 \verb|<car>| est un caract\xE8re. L'entier que cela repr\xE9sente est le code du caract\xE8re \verb|<car>| (voir page~\pageref{definition.entier}). Nous allons \xE9galement tirer parti du fait que les codes des caract\xE8res de \xAB\verb|a|\xBB \xE0 \xAB\verb|z|\xBB sont des entiers cons\xE9cutifs. Par cons\xE9quent, \verb|<car>| est une lettre minuscule si l'entier \verb|`<car>| est compris entre les entiers \verb|`a| et \verb|`z| (bornes comprises).
+
+\subsection{Programmer un test : m\xE9thodes}
+Compte tenu du fait qu'il existe plusieurs m\xE9thodes pour programmer la \emph{structure} d'une telle macro, nous allons en envisager plusieurs et elles seront num\xE9rot\xE9es pour pouvoir facilement y faire r\xE9f\xE9rence plus tard.
+
+\subsubsection{M\xE9thode \no1 : intuitive}
+Une fa\xE7on intuitive de le faire est de faire lire les trois arguments par la macro :
+
+\begin{enumerate}[label={}]
+	\item \verb|#1| : le caract\xE8re \verb|<car>| \xE0 tester;
+	\item \verb|#2| : le \verb|<code vrai>|, ex\xE9cut\xE9 si le test est vrai;
+	\item \verb|#3| : le \verb|<code faux>|, ex\xE9cut\xE9 si le test est faux.
+\end{enumerate}
+
+Ensuite, il suffit d'imbriquer 2 tests comme nous l'avons d\xE9j\xE0 fait et selon l'issue de ces tests, \xE9crire \xE0 l'int\xE9rieur des branches des tests les arguments \verb-#2- ou \verb-#3- :
+
+\showcode/\def\ifletter#1#2#3{%
+	\ifnum`#1<`a% si le caract\xE8re est avant "a"\xA4\tidx*{ifnum}\xA4
+		#3% ex\xE9cuter "<code faux>"
+	\else% sinon
+		\ifnum`#1>`z% si le caract\xE8re est apr\xE8s "z"
+			#3% ex\xE9cuter "<code faux>"
+		\else% dans tous les autres cas
+			#2% "#1" est une lettre : ex\xE9cuter "<code vrai>"
+		\fi
+	\fi}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}/
+
+Il y a une certaine inutilit\xE9 dans ce code qui est de lire \verb-#2- et \verb-#3- par la macro \verb|\ifletter| pour les r\xE9\xE9crire plus loin dans le code. L'id\xE9al serait de ne lire que l'argument \verb-#1-, de faire le test et selon l'issue, de lire l'un des deux arguments qui suivent (et qui n'ont pas encore \xE9t\xE9 lus).
+
+\subsubsection{M\xE9thode \no2 : \texttt{\char`\\firstoftwo} et {\char`\\secondoftwo}}
+Les macros \xA7\firstoftwo et \xA7\secondoftwo que nous avons \xE9crites \xE0 la page~\pageref{firstoftwo} permettent de s\xE9lectionner un argument parmi deux. C'est d'ailleurs parce qu'elles sont utilis\xE9es \xE0 l'issue d'un test qu'elles sont si fr\xE9quemment rencontr\xE9es en programmation. La fa\xE7on na\xEFve de les placer dans les branches des tests serait d'\xE9crire :
+
+\centrecode*-\def\ifletter#1{%
+	\ifnum`#1<`a
+		\secondoftwo
+	\else
+		\ifnum`#1>`z
+			\secondoftwo
+		\else
+			\firstoftwo
+		\fi
+	\fi}-
+
+\noindent Mais agir de cette fa\xE7on provoquerait des r\xE9sultats inattendus et des erreurs de compilation. Il ne faut surtout pas oublier que les \tidx{else} et les \tidx{fi} ne sont pas r\xE9sorb\xE9s lorsque le test est fait, mais restent en place pour \xEAtre d\xE9velopp\xE9s (et \xE9limin\xE9s) plus tard ! Il faut donc faire disparaitre les \tidx{else} et les \tidx{fi} \emph{avant} que \xA7\firstoftwo ou \xA7\secondoftwo n'entrent en jeu et ne les prennent \xE0 tort comme leurs arguments ! Pour cela, nous savons qu'il faut les 1-d\xE9velopper. Le cas du premier \xA7\secondoftwo est le plus simple : nous mettrons donc un \idx\expandafter avant lui pour faire disparaitre les 7 derni\xE8res lignes.
+
+Pour le test imbriqu\xE9, c'est un peu plus compliqu\xE9. Mettre un \idx\expandafter devant \xA7\firstoftwo et \xA7\secondoftwo fait disparaitre que le \tidx{else} ou le \tidx{fi} int\xE9rieur. Il restera encore le \tidx{fi} de la derni\xE8re ligne \xE0 1-d\xE9velopper. Nous devons donc cr\xE9er un pont d'\idx\expandafter \xE0 deux passes pour 1-d\xE9velopper d'abord le \tidx{else} ou le \tidx{fi} int\xE9rieur puis le \tidx{fi} final.
+
+Voici donc comment coder la macro \verb|\ifletter| :
+
+\showcode/\def\ifletter#1{%\xA4\tidx*{ifnum}\xA4
+	\ifnum`#1<`a
+		\expandafter\secondoftwo% \expandafter 1-d\xE9veloppe "\else...\fi"\xA4\xA7*\secondoftwo\xA4
+	\else
+		\ifnum`#1>`z
+			\expandafter\expandafter\expandafter% 1-d\xE9veloppe "\else...\fi" puis "\fi"
+			\secondoftwo\xA4\xA7*\secondoftwo\xA4
+		\else
+			\expandafter\expandafter\expandafter%1-d\xE9veloppe "\fi" puis "\fi"
+			\firstoftwo\xA4\xA7*\firstoftwo\xA4
+		\fi
+	\fi}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}/
+
+La macro \verb|\ifetter| est purement d\xE9veloppable (\xE0 condition bien s\xFBr que les instructions contenues dans \verb|<code vrai>| et \verb|<code faux>| le soient).
+
+\subsubsection{M\xE9thode \no3 : \texttt{\char`\\romannumeral}}
+La m\xE9thode pr\xE9c\xE9dente produit une macro purement d\xE9veloppable, mais le nombre de d\xE9veloppements \xE0 faire pour arriver au \verb|<code vrai>| ou \verb|<code faux>| d\xE9pend du nombre de tests faits et donc, d\xE9pend de l'argument. Ne pas savoir \xE0 l'avance combien de d\xE9veloppements sont n\xE9cessaires pour arriver au r\xE9sultat escompt\xE9 peut se r\xE9v\xE9ler g\xEAnant dans certains cas particuliers.
+
+\Qu el que soit son argument, faisons en sorte que la macro \verb-\ifletter- se d\xE9veloppe en \verb-<code vrai>- ou  \verb-<code faux>- en deux d\xE9veloppements. L'astuce, nous l'avons d\xE9j\xE0 vu, consiste \xE0 initier une zone de d\xE9veloppement maximal avec la primitive \idx\romannumeral et stopper ce d\xE9veloppement maximal au bon moment en ajoutant \verb*|0 | ou \idx\z@ (ou tout autre nombre n\xE9gatif). Ce moment est ici le d\xE9but de \verb-<code vrai>- ou  \verb-<code faux>- et donc, pour ins\xE9rer cet ajout, il faut lire les deux derniers arguments de la macro \verb|\ifletter| :
+
+\showcode/\def\ifletter#1#2#3{%
+	\romannumeral % <- initie le d\xE9veloppement maximal\xA4\idx*\romannumeral\xA4
+	\ifnum`#1<`a
+		\expandafter\secondoftwo\xA4\xA7*\secondoftwo\xA4
+	\else
+		\ifnum`#1>`z
+			\expandafter\expandafter\expandafter\secondoftwo\xA4\xA7*\secondoftwo\xA4
+		\else
+			\expandafter\expandafter\expandafter\firstoftwo\xA4\xA7*\firstoftwo\xA4
+		\fi
+	\fi{0 #2}{0 #3}% <- "0 " stoppe le d\xE9veloppement maximal
+}
+\long\def\>#1<{\detokenize{#1}}\xA4\idx*\detokenize\idx*\long\xA4
+a) \expandafter\expandafter\expandafter\>\ifletter{0}{vrai}{faux}<\qquad
+b) \expandafter\expandafter\expandafter\>\ifletter{x}{vrai}{faux}</
+
+\subsubsection{M\xE9thode \no4 : macro auxiliaire}
+Pour s'\xE9pargner tous ces \idx\expandafter et si nous n'avons pas besoin d'une macro purement d\xE9veloppable, il est judicieux de s'aider d'une macro auxiliaire --~appelons-la \verb|\donext|~-- que l'on rend \idx\let-\xE9gale \xE0 \xA7\firstoftwo ou \xA7\secondoftwo dans les branches des tests. Cette macro sera appel\xE9e \xE0 la fin, apr\xE8s \xEAtre sorti des branches des tests :
+
+\showcode/\def\ifletter#1{%\xA4\tidx*{ifnum}\xA4
+	\ifnum`#1<`a
+		\let\donext=\secondoftwo\xA4\xA7*\secondoftwo\xA4
+	\else
+		\ifnum`#1>`z
+			\let\donext=\secondoftwo\xA4\xA7*\secondoftwo\xA4
+		\else
+			\let\donext=\firstoftwo\xA4\xA7*\firstoftwo\xA4
+		\fi
+	\fi
+	\donext% ex\xE9cuter l'action d\xE9cid\xE9e ci-dessus
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}/
+
+\subsubsection{M\xE9thode \no5 : \texttt{\char`\\csname} et \texttt{\char`\\endcsname}}
+La m\xE9thode de loin la plus \xE9l\xE9gante, mais h\xE9las la plus lente est d'\xE9crire les tests \emph{\xE0 l'int\xE9rieur} de la paire \idx\csname\linebreak[1]\verb-...-\linebreak[1]\idx\endcsname. Une fois que les tests seront d\xE9velopp\xE9s, que les branches inutiles auront disparu suite au d\xE9veloppement maximal initi\xE9 par \idx\csname, il devra rester entre \idx\csname et \idx\endcsname soit \xAB\texttt{firstoftwo}\xBB, soit \xAB\texttt{secondoftwo}\xBB. La fin du mot \xAB\verb|oftwo|\xBB \xE9tant commune \xE0 toutes les issues possibles, il est possible de \emph{factoriser} le code en mettant cette partie de mot \xE0 la toute fin, juste avant le \idx\endcsname. Cette m\xE9thode pr\xE9sente l'avantage de donner \verb|<code vrai>| ou \verb|<code faux>| en trois d\xE9veloppements, quel que soit l'argument donn\xE9 \xE0 \verb|\ifletter| :
+
+\showcode/\def\ifletter#1{%\xA4\idx\csname\tidx{ifnum}\xA4
+	\csname
+		\ifnum`#1<`a
+			second% <- commenter la fin de ligne pour \xE9viter un
+		\else%          espace parasite dans le nom de la macro cr\xE9\xE9e
+			\ifnum`#1>`z
+				second%
+			\else
+				first%
+			\fi
+		\fi
+		oftwo%
+	\endcsname
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}/
+
+\begin{exercice}
+Comment faudrait-il modifier ce dernier code pour que \verb|\ifletter| teste si son argument est une lettre de l'alphabet, aussi bien minuscule que majuscule ?
+\solution
+La primitive \idx\lowercase est utile dans ce cas puisqu'elle change toutes les lettres en lettres minuscules et laisse inchang\xE9es les s\xE9quences de contr\xF4le :
+
+\showcode/\def\ifletter#1{%\xA4\idx*\lowercase\idx*\csname\tidx*{ifnum}\xA4
+	\lowercase{\csname
+		\ifnum`#1<`a second%
+		\else
+			\ifnum`#1>`z second\else first\fi
+		\fi
+	oftwo\endcsname\xA4\idx*\endcsname\xA4
+	}%
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}/
+
+H\xE9las, la primitive \idx\lowercase n'est \emph{pas} d\xE9veloppable ! Autrement dit, elle n'a pas vocation \xE0 \xEAtre \emph{d\xE9velopp\xE9e,} mais \emph{ex\xE9cut\xE9e} c'est-\xE0-dire que le remplacement des lettres par des lettres minuscules n'est pas fait sur la pile de \TeX{} mais plus tard, en interne, lors de l'ex\xE9cution. Le code suivant montre qu'un \idx\edef ne provoque aucun d\xE9veloppement sur cette primitive :
+
+\showcode/\edef\foo{\lowercase{AbCd}}\meaning\foo/
+
+Pour en revenir \xE0 la macro \verb|\ifletter|, si nous souhaitons qu'elle reste purement d\xE9veloppable, il faut lui faire ex\xE9cuter deux tests de plus (ce qui suppose autant d'imbrications suppl\xE9mentaires) pour tester la place qu'occupe l'entier \verb|`<car>| par rapport aux entiers \verb|`A| et \verb|`Z| :
+
+\showcode/\def\ifletter#1{%\xA4\idx*\csname\xA4
+	\csname
+		\ifnum`#1<`A second%
+		\else
+			\ifnum`#1<`Z first%\xA4\tidx*{ifnum}\xA4
+			\else
+				\ifnum`#1>`a
+					\ifnum`#1<`z
+						first%
+					\else
+						second%
+					\fi
+				\else
+					second%
+				\fi
+			\fi
+		\fi
+		oftwo%
+	\endcsname
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}\qquad
+d) \edef\foo{\ifletter{x}{vrai}{faux}}\meaning\foo\qquad\xA4\idx*\meaning\xA4
+e) \edef\foo{\ifletter{=}{vrai}{faux}}\meaning\foo/
+
+Ici encore, 3 d\xE9veloppements sont n\xE9cessaires pour que \verb|\ifletter{<car>}{<vrai>}{<faux>}| se d\xE9veloppe en \verb|<vrai>| ou \verb|<faux>| comme le montre ce sch\xE9ma o\xF9 une fl\xE8che repr\xE9sente un d\xE9veloppement :
+
+\begin{centrage}
+\small
+\verb|\ifletter{<car>}|%
+$\longrightarrow$%
+\verb|\csname...\endcsname|%
+$\longrightarrow
+\vcenter{\hbox{\xA7\firstoftwo}\hbox{ou}\hbox{\xA7\secondoftwo}}
+\longrightarrow
+\vcenter{\hbox{\verb|<vrai>|}\hbox{ou}\hbox{\verb|<faux>|}}$
+\end{centrage}
+\end{exercice}
+
+\subsubsection{Retour sur la m\xE9thode \no1}
+Bien que la m\xE9thode \no1 (dont le code est rappel\xE9 ci-dessous) semble identique aux autres m\xE9thodes, il n'en est rien !
+
+\centrecode*-\def\ifletter#1#2#3{%
+	\ifnum`#1<`a
+		#3%
+	\else
+		\ifnum`#1>`z
+			#3%
+		\else
+			#2%
+		\fi
+	\fi}-
+
+Le fait que les arguments \verb|#2| et \verb|#3| soient ins\xE9r\xE9s \emph{dans} les branches du test (alors qu'avec \xA7\firstoftwo et \xA7\secondoftwo, ils restent au dehors pour les autres m\xE9thodes) signifie que ces arguments peuvent agir sur ce qui se trouve apr\xE8s eux dans ces m\xEAmes branches\ldots{} Et \xE9ventuellement tout casser ! Imaginons par exemple que l'argument \verb|#3| soit la macro \xA7\gobtwo et que le premier test soit vrai. Lorsque \verb|#3|, c'est-\xE0-dire la macro \xA7\gobtwo va \xEAtre ex\xE9cut\xE9e, elle va capturer les deux arguments qui la suivent pour les faire disparaitre. Tout va se passer comme si un \tidx{else} et un \tidx{ifnum} \xE9taient retir\xE9s du texte de remplacement. Ces deux primitives n'existant plus, l'\xE9quilibre entre les \tidx{fi} et les primitives de test est rompu et \TeX{}, lorsqu'il rencontrera un \tidx{fi} exc\xE9dentaire, \xE9mettra l'erreur de compilation \xAB\texttt{Extra \char`\\fi}\xBB.
+
+Il est donc particuli\xE8rement important qu'une macro effectuant un test avec la syntaxe
+
+\centrecode-\if<test><arguments>{<code vrai>}{<code faux>}<code qui suit>-
+
+\noindent rejette \emph{au-dehors} des branches des tests les arguments \verb|<code vrai>| et \verb|<code faux>| de telle sorte que le code qu'ils contiennent puisse \xE9ventuellement agir sur le \verb|<code qui suit>|. La m\xE9thode \no1, puisque contrevenant \xE0 ce principe, est une m\xE9thode \xE0 d\xE9conseiller.\xA7*\ifletter[|)]%
+
+\subsection{Exercices sur les entiers}
+\begin{exercice}
+Programmer une macro \xA7\ifinside[|(] dont voici la syntaxe :
+
+\begin{centrage}
+	\small\xA7\ifinside $n$\verb|[|$a$\verb|,|$b$\verb|]{<code vrai>}{<code faux>}|
+\end{centrage}
+
+o\xF9 $n$, $a$ et $b$ sont 3 entiers avec $a\leqslant b$. La macro \xA7\ifinside teste si $n$ appartient \xE0 l'intervalle ferm\xE9 $[a\;\string;\;b]$.
+\solution
+
+La premi\xE8re id\xE9e est d'imbriquer des tests sur les in\xE9galit\xE9s. Il faut ex\xE9cuter \verb|<code faux>| si $n<a$ ou si $n>b$, et ex\xE9cuter \verb|<code vrai>| sinon :
+
+\showcode/\def\ifinside#1[#2,#3]{%
+	\csname
+		\ifnum#1<#2 second% si n<a, <code faux>
+		\else
+			\ifnum#1>#3 second% si n>b, <code faux>
+			\else       first%  sinon, <code vrai>
+			\fi
+		\fi
+	oftwo%
+	\endcsname
+}
+a) \ifinside 3[1,8]{oui}{non}\qquad
+b) \ifinside -7[-20,-11]{oui}{non}\qquad
+c) \ifinside 9[0,6]{oui}{non}\qquad
+d) \ifinside -1[-5,1]{oui}{non}/
+
+Une autre approche serait de consid\xE9rer l'entier
+
+\[(n-a)(n-b)\]
+
+Si cet entier est n\xE9gatif ou nul, $n$ est dans l'intervalle. Autrement dit, \xA7\ifinside doit ex\xE9cuter \verb|<code faux>| lorsque cet entier est strictement positif. En s'aidant de \idx\numexpr, un seul test \tidx{ifnum} devient alors n\xE9cessaire pour d\xE9cider si $n$ est dans l'intervalle ou pas\label{ifinside} :
+
+\showcode/\def\ifinside#1[#2,#3]{%
+	\ifnum\numexpr(#1-#2)*(#1-#3)\relax>0
+		\expandafter\secondoftwo
+	\else
+		\expandafter\firstoftwo
+	\fi
+}
+a) \ifinside 3[1,8]{oui}{non}\qquad
+b) \ifinside -7[-20,-11]{oui}{non}\qquad
+c) \ifinside 9[0,6]{oui}{non}\qquad
+d) \ifinside -1[-5,1]{oui}{non}/\xA7*\ifinside[|)]
+\end{exercice}
+
+\begin{exercice}
+Programmer une macro \xA7\absval\verb-{entier}-, purement d\xE9veloppable et qui se d\xE9veloppe en la valeur absolue de l'entier.
+\solution
+La premi\xE8re id\xE9e est de tester si l'entier est n\xE9gatif auquel cas, nous prendrons l'oppos\xE9 de ce nombre en mettant un signe \xAB\verb+-+\xBB devant :
+
+\showcode/\def\absval#1{%\xA4\idx*\number\tidx*{ifnum}\xA7*\absval\xA4
+	\ifnum#1<0 \number-#1
+	\else      \number#1
+	\fi}
+a) \absval{-87}\qquad b) \absval{75}\qquad c) \absval{0}\xA4\xA7*\absval\xA4/
+
+Mais la meilleure solution serait de se servir du fait que la primitive \idx\number d\xE9veloppe au maximum tout ce qu'elle trouve jusqu'\xE0 trouver un caract\xE8re qui ne peut pas appartenir \xE0 un nombre. Nous pouvons donc mettre le test \emph{dans} le nombre \xE9valu\xE9 par \idx\number, c'est-\xE0-dire apr\xE8s cette primitive. Le d\xE9veloppement maximal de ce test laissera \xAB\verb+-+\xBB si le nombre est n\xE9gatif et rien sinon :
+
+\showcode/\def\absval#1{\number\ifnum#1<0 -\fi#1 }\xA4\xA7*\absval\xA4
+a) \absval{-87}\qquad b) \absval{75}\qquad c) \absval{0}\xA4\xA7*\absval\xA4/
+
+Un fonctionnalit\xE9 int\xE9ressante est d'autoriser des expressions arithm\xE9tiques dans l'argument de \xA7\absval. Pour ce faire, nous pouvons \xE9valuer cet argument avec \idx\numexpr :
+
+\showcode/\def\absval#1{\number\ifnum\numexpr#1\relax<0 -\fi\numexpr#1\relax}\xA4\idx*\numexpr\idx*\relax\xA7*\absval\xA4
+a) \absval{-87}\qquad
+b) \absval{75}\qquad
+c) \absval{0}\qquad
+d) \absval{-20+13}\qquad% -7 affich\xE9 7
+e) \absval{5-3*(-4)+10-50}% -23 affich\xE9 23\xA4\xA7*\absval\xA4/
+
+Le seul inconv\xE9nient est que nous \xE9valuons \emph{deux} fois l'expression arithm\xE9tique \verb|#1| ce qui est redondant et source de ralentissement. Un  programmeur rigoureux d\xE9composerait le travail et \xE9crirait deux macros. La premi\xE8re serait charg\xE9e d'\xE9valuer l'expression arithm\xE9tique et de passer comme argument \xE0 la seconde macro le \emph{nombre explicitement \xE9crit} qui a \xE9t\xE9 obtenu. Celle-ci serait charg\xE9e de donner la valeur absolue de son argument :
+
+\showcode/\catcode`\@11
+\def\absval#1{\exparg\absval at i{\number\numexpr#1\relax}}\xA4\idx*\numexpr\idx*\relax\xA7*\absval\xA7*\exparg\xA4
+\def\absval at i#1{\number\ifnum#1<\z at -\fi#1 }\xA4\idx*\number\idx*\z@\xA4
+\catcode`\@12
+a) \absval{-87}\qquad
+b) \absval{75}\qquad
+c) \absval{0}\qquad
+d) \absval{-20+13}\qquad% r\xE9sultat -7 qui est affich\xE9 7
+e) \absval{5-3*(-4)+10-50}% r\xE9sultat -23 qui est affich\xE9 23\xA4\xA7*\absval\xA4/
+\end{exercice}
+
+\label{intdiv}\begin{exercice}
+Nous avions vu au chapitre pr\xE9c\xE9dent la macro \xA7\truncdiv qui appliquait la formule suivante pour calculer la troncature du quotient de $x$ par $y$ en utilisant la division de \idx\numexpr :
+
+\[\frac{x-\frac{y-1}2}y\]
+
+Voici le code de la macro tel que nous l'avions \xE9labor\xE9:
+
+\centrecode|\def\truncdiv#1#2{\numexpr(#1-(#2-1)/2)/#2\relax}|\xA7*\truncdiv
+
+La formule n'\xE9tant valable que pour $x$ et $y$ positifs, cette macro donnait des r\xE9sultats erron\xE9s pour des arguments n\xE9gatifs. Modifier la macro \xA7\truncdiv pour qu'elle donne le bon r\xE9sultat, quels que soient les signes de ses deux arguments.
+\solution
+D\xE9j\xE0, la formule donn\xE9e est \xE9quivalente \xE0
+\[\frac{2x-y+1}{2y}\]
+qui sera sans doute un peu plus rapide puisqu'il n'y a qu'une seule division.
+
+Puisqu'elle n'est valable que pour les entiers positifs, nous allons reprendre le code de la macro \xA7\truncdiv donn\xE9 dans l'\xE9nonc\xE9 en rempla\xE7ant les arguments par leur valeur absolue. Pour que le quotient final tienne compte des signes des arguments, nous allons multiplier le quotient par 1, pr\xE9c\xE9d\xE9 du signe du premier argument et du signe du second. De cette fa\xE7on, s'ils sont tous les deux positifs, nous aurons \verb|--1| et la primitive \idx\number sait que ce nombre est 1. Si l'on note $\sigma_x$ le signe de $x$, cela donne
+
+\[\sigma_x\sigma_y1\times\frac{2|x|-|y|+1}{2|y|}\]
+
+Pour cela, reprenons la macro \xA7\absval et cr\xE9ons une macro \xA7\sgn qui se d\xE9veloppe en \xAB\verb|-|\xBB si son argument est strictement n\xE9gatif :
+
+\showcode|\def\sgn#1{\ifnum#1<0 -\fi}\xA4\xA7*\sgn\xA4
+\def\truncdiv#1#2{%\xA4\xA7*\truncdiv\xA7*\absval\xA7*\absval\xA7*\truncdiv\xA4
+	\numexpr
+		\sgn{#1}\sgn{#2}1*% multiplie le quotient ci-dessous par +1 ou -1\xA4\xA7*\sgn\xA4
+		(2*\absval{#1}-\absval{#2}+1)/(2*\absval{#2})\xA4\xA7*\absval\xA4
+	\relax
+}
+a) \number\truncdiv{-8}3\qquad
+b) \number\truncdiv{-8}{-3}\qquad
+c) \number\truncdiv8{-3}\qquad
+d) \number\truncdiv{0}{-5}\xA4\xA7*\truncdiv\xA4|
+
+Une optimisation possible de la formule est d'\xE9crire au d\xE9nominateur $2y$ (qui contient le signe de $y$) et supprimer $\sigma_y$ au d\xE9but. Il est aussi possible de d\xE9placer $\sigma_x$ au d\xE9nominateur :
+
+\[\frac{2|x|-|y|+1}{\sigma_x2y}\]
+
+Si $y$ est une expression arithm\xE9tique, il est plus prudent de mettre \verb|#2| (qui repr\xE9sente $y$) entre parenth\xE8ses au d\xE9nominateur. Cela nous donnerait la macro
+
+\centrecode|\def\truncdiv#1#2{%\xA4\xA7*\truncdiv\xA4
+	\numexpr(2*\absval{#1}-\absval{#2}+1)/(\sgn{#1}2*(#2))\relax\xA4\xA7*\absval\xA7*\sgn\xA4
+}|
+
+En l'\xE9tat, elle n'est pas satisfaisante, car si \verb|#1| est une expression arithm\xE9tique, \xA7\sgn\verb|{#1}| va provoquer une erreur puisque rien n'est pr\xE9vu pour \xE9valuer l'argument de \xA7\sgn. De plus, l'argument \verb|#2| est \xE9valu\xE9 \emph{deux} fois : une fois par \xA7\absval et une autre dans la parenth\xE8se au d\xE9nominateur.
+
+Il faut mettre un peu d'ordre et d\xE9cider que les deux arguments de \xA7\truncdiv doivent tout d'abord \xEAtre calcul\xE9s par une premi\xE8re macro puis \xEAtre transmis en tant que nombres explicitement \xE9crits \xE0 une seconde macro qui fera le calcul. Comme les arguments sont d\xE9j\xE0 calcul\xE9s, il ne faut pas que \verb|absval| ne les calcule \xE0 nouveau. Abandonnons donc cette version de \xA7\absval pour \xE9crire \xAB\xA7\sgn\verb|{<entier>}<entier>|\xBB ce qui arithm\xE9tiquement, est la valeur absolue de l'\verb|<entier>| :
+
+\showcode|\catcode`\@11
+\def\sgn#1{\ifnum#1<\z at -\fi}\xA4\idx*\z@\xA7*\sgn\xA4
+\def\truncdiv#1#2{%
+	\exptwoargs\truncdiv at i{\number\numexpr#1\relax}{\number\numexpr#2\relax}%\xA4\xA7*\truncdiv\xA7*\exptwoargs\idx*\number\xA7*\truncdiv\xA4
+}
+\def\truncdiv at i#1#2{%\xA4\xA7*\truncdiv\xA4
+	\numexpr(2*\sgn{#1}#1-\sgn{#2}#2+1)/(\sgn{#1}2*#2)\relax\xA4\xA7*\sgn\xA4
+}
+\catcode`\@12
+a) \number\truncdiv{-8}3\qquad
+b) \number\truncdiv{-8}{-3}\qquad
+c) \number\truncdiv8{-3}\qquad
+d) \number\truncdiv{0}{-5}\qquad
+e) \number\truncdiv{20+2*3}{4-5*2}% 26/(-6) doit donner -4\xA4\xA7*\truncdiv\xA4|
+\end{exercice}
+
+\begin{exercice}
+\def\siecle#1{%
+	\ifnum#1=0 \else
+		\uppercase\expandafter{\romannumeral\ifnum#1<0-\fi#1 }%
+		\raise1ex \hbox{e\ifnum#1=1 r\fi}
+		si\xE8cle \ifnum#1<0 avant J.C.\fi
+	\fi
+}
+\xC9laborer une macro \xA7\siecle\verb|{<nombre>}| qui, selon le nombre contenu dans son argument, adapte l'\xE9criture des si\xE8cles :\medbreak
+\begin{tabular}{>{\ttfamily\hfill}m{0.5\linewidth}<{\kern1em \normalfont affiche\kern1em}@{}l}
+\string\siecle\{19\}&\siecle{19}\\
+\string\siecle\{-3\}&\siecle{-3}\\
+\string\siecle\{1\}&\siecle{1}\\
+\string\siecle\{0\}&\siecle{0}<vide>
+\end{tabular}
+
+Pour sur\xE9lever un texte enferm\xE9 dans une boite (ici une \idx\hbox), on aura recours \xE0 la primitive \idx\raise et on \xE9crira :
+
+\centrecode-\raise1ex \hbox{<exposant>}-
+
+pour \xE9lever l'\verb|<exposant>| de \verb|1ex|.
+\solution
+Il s'agit de faire quelque chose sauf si l'argument est nul. Nous pouvons donc \xE9crire
+
+\centrecode-\ifnum#1=0 \else<action \xE0 faire>\fi-
+
+\noindent mais le moteur \idx\eTeX{}\idx*{moteur!etex} dispose de la primitive \tidx{unless} qui, plac\xE9e devant un test, \xE9change les branches correspondant aux issues du test : ce qui est entre le test et \tidx{else} est \xE9chang\xE9 avec ce qui est entre \tidx{else} et \tidx{fi}. Nous \xE9crirons donc ici :
+
+\centrecode-\unless\ifnum#1=0 <action \xE0 faire>\fi-
+
+Pour obtenir des chiffres romains en majuscule, nous allons utiliser la primitive \idx\uppercase en ayant pris soin de d\xE9velopper au pr\xE9alable son argument traduit en chiffres romains par \idx\romannumeral. Pour \xEAtre surs que le nombre \xE9valu\xE9 est toujours positif, nous \xE9crirons \idx\romannumeral\xA7\absval\verb|{#1}|.
+
+Pour l'\xAB exposant \xBB, nous allons donc utiliser la primitive \idx\raise qui a la facult\xE9 d'\xE9lever --~ici d'\verb|1ex|~-- la boite horizontale qui la suit. Cette boite contiendra \xAB\verb|e|\xBB suivi, si la valeur absolue de l'argument est 1, d'un \xAB\verb|r|\xBB. Il faudra ensuite ins\xE9rer \xABav. J.-C.\xBB si l'argument \verb|#1| est strictement n\xE9gatif. Le code est finalement assez facilement lisible :
+
+\showcode/\def\siecle#1{%\xA4\xA7*\siecle\xA4
+	\unless\ifnum#1=0 % ne faire quelque chose que si #1 diff\xE9rent de 0\xA4\tidx*{unless}\xA4
+		\uppercase\expandafter{\romannumeral\absval{#1}}% chiffres romains majuscules\xA4\defline\aaa\idx*\uppercase\idx*\romannumeral\xA7*\absval\xA4
+		\raise 1ex \hbox{e\ifnum\absval{#1}=1 r\fi} si\xE8cle% affiche l'exposant puis "si\xE8cle"
+		\ifnum#1<0 {} av. J.-C.\fi% affiche si besoin "av. J.-C."\xA4\idx*\raise\idx*\hbox\xA7*\absval\tidx*{ifnum}\xA4
+	\fi
+}
+a) \siecle{19}\qquad
+b) \siecle{-3}\qquad
+c) \siecle{1}\qquad
+d) \siecle{0}\qquad
+e) \siecle{-1}\xA4\xA7*\siecle\xA4/
+
+Le \idx\expandafter de la ligne \no\aaa{} est automatiquement d\xE9velopp\xE9 puisque \idx\uppercase fait partie de ces macros qui doivent \xEAtre suivie d'une accolade ouvrante et qui donc, d\xE9veloppe au maximum ce qui est entre elle et cette accolade. Le d\xE9veloppement de cet \idx\expandafter provoque celui de \idx\romannumeral qui convertit le nombre en chiffres romains avant que \idx\uppercase ne joue son r\xF4le et \xE9crive les chiffres romains en majuscule.
+\end{exercice}
+
+\begin{exercice}
+Programmer une macro \xA7\hdif[|(]\verb|{h:m:s}{h':m':s'}| qui calcule le temps qui s'est \xE9coul\xE9 entre l'heure \verb|h:m:s| et l'heure \verb|h':m':s'| qui lui est ant\xE9rieure. L'affichage se fera en heures, minutes et secondes :\medbreak
+
+\begin{tabular}{>{\ttfamily\hfill}m{0.6\linewidth}<{\kern1em \normalfont affiche\kern1em}@{}l}
+\verb|\hdif{18:51:20}{9:20:10}|&\hdif{10:51:20}{9:20:10}\\
+\verb|\hdif{14:20:0}{13:50:0}|&\hdif{14:20:0}{13:50:0}\\
+\verb|\hdif{7:50:20}{5:50:20}|&\hdif{7:50:20}{5:50:20}\\
+\verb|\hdif{7:50:10}{6:50:20}|&\hdif{7:50:10}{6:50:20}\\
+\verb|\hdif{20:00:00}{19:59:15}|&\hdif{20:00:00}{19:59:15}\\
+\verb|\hdif{17:13:15}{14:12:45}|&\hdif{17:13:15}{14:12:45}
+\end{tabular}
+\solution
+La soustraction de dur\xE9es exprim\xE9es en heures, minutes et secondes se fait comme au coll\xE8ge :
+\begin{enumerate}
+	\item effectuer les soustractions ind\xE9pendamment entre les heures, les minutes et les secondes ;
+	\item si le nombre de secondes est strictement n\xE9gatif, l'augmenter de 60 et soustraire 1 au nombre de minutes ;
+	\item puis, si le nombre de minutes est strictement n\xE9gatif, l'augmenter de 60 et soustraire 1 au nombre d'heures ;
+\end{enumerate}
+
+L'algorithme s'annonce finalement assez simple.
+
+Comme pour nous en France, le caract\xE8re \xAB\verb|:|\xBB est parfois rendu actif\footnote{Afin qu'il ins\xE8re une espace ins\xE9cable du type \texttt{\string\kern\codeelement{dimension}} juste avant  \xAB\texttt{\string\string\string\:}\xBB.}, il faut ouvrir un groupe semi-simple et changer son code de cat\xE9gorie \emph{avant} de lire l'argument de \verb|\hdif|. Le groupe semi-simple sera ferm\xE9 \xE0 la fin, apr\xE8s l'affichage.
+
+La principale m\xE9thode de programmation ici consiste \xE0 passer les arguments \xE0 une macro \xE0 arguments d\xE9limit\xE9s \verb|\hdiff at ii| qui isolera les heures, minutes et secondes, effectuera les soustractions entre nombres exprim\xE9s dans la m\xEAme unit\xE9 et ajustera les r\xE9sultats s'ils sont n\xE9gatifs. Pour ce qui est de l'affichage du r\xE9sultat, les nombres d'heures, minutes et secondes ne seront affich\xE9s que s'ils ne sont pas nuls. Enfin, du c\xF4t\xE9 de la typographie, une macro temporaire \verb|\inter at space|, vide au d\xE9but, sera rendue \idx\let-\xE9gale \xE0 un espace d\xE8s qu'un nombre (d'heures ou de minutes) sera affich\xE9. Elle sera ins\xE9r\xE9e avant le nombre suivant et ainsi cr\xE9era une espace avant minutes ou avant les secondes si celles-ci ont \xE9t\xE9 pr\xE9c\xE9d\xE9es par l'affichage d'un nombre.
+
+Voici le code comment\xE9 :
+
+\showcode|\catcode`\@11
+\edef\saved at catcode{\number\catcode`\:}% sauvegarde du catcode de ":"
+\catcode`\:12 % ":" est d\xE9sormais un caract\xE8re non actif normal
+\def\hdif{%
+	\begingroup% ouvrir un groupe semi-simple\xA4\idx*\begingroup\xA4
+		\catcode`\:12 % modifier le catcode de ":"
+		\hdif at i% aller lire les deux arguments
+}
+
+\def\hdif at i#1#2{% lit les 2 arguments
+		\hdif at ii#1-#2\@nil% et les transmet \xE0 la macro \xE0 argument d\xE9limit\xE9s
+}
+
+\def\hdif at ii#1:#2:#3-#4:#5:#6\@nil{%
+		%%%%%% calcul des nombres \xE0 afficher %%%%%%
+		\edef\nb at hrs{\number\numexpr#1-#4\relax}% diff\xE9rence des heures\xA4\idx*\number\idx*\numexpr\xA4
+		\edef\nb at min{\number\numexpr#2-#5\relax}% diff\xE9rence des minutes
+		\edef\nb at sec{\number\numexpr#3-#6\relax}% diff\xE9rence des secondes
+		\ifnum\nb at sec<\z@ % si la diff\xE9rence des secondes est <0\xA4\tidx*{ifnum}\idx*\z@\xA4
+			\edef\nb at sec{\number\numexpr\nb at sec+60\relax}% ajouter 60 sec
+			\edef\nb at min{\number\numexpr\nb at min-1\relax}% enlever 1 aux minutes
+		\fi
+		\ifnum\nb at min<\z@ % si les minutes sont <0
+			\edef\nb at min{\number\numexpr\nb at min+60\relax}% ajouter 60 min
+			\edef\nb at hrs{\number\numexpr\nb at hrs-1\relax}% enlever 1 aux heures
+		\fi
+		%%%%%% affichage du r\xE9sultat %%%%%%
+		\let\inter at space\empty% pas d'espace avant un nombre pour l'instant
+		\ifnum\nb at hrs>\z@ % si les heures sont >0
+			\nb at hrs h% afficher les heures et "h"
+			\let\inter at space\space% espace pour plus tard
+		\fi
+		\ifnum\nb at min>\z@ % si les minutes sont >0
+			\inter at space% afficher une espace \xE9ventuelle
+			\nb at min min% afficher les minutes et "min"
+			\let\inter at space\space\xA4\idx*\space\xA4
+		\fi
+		\ifnum\nb at sec>\z@ % si les secondes sont >0\xA4\idx*\z@\xA4
+			\inter at space% afficher une espace \xE9ventuelle
+			\nb at sec s% afficher les secondes et "s"
+		\fi
+	\endgroup% fermer le groupe ouvert au d\xE9but\xA4\idx*\endgroup\xA4
+}
+\catcode`\:=\saved at catcode\relax% restaure le code de cat\xE9gorie de ":"
+\catcode`\@12
+a) \hdif{10:51:20}{9:20:10}\par
+b) \hdif{14:20:0}{13:50:0}\par
+c) \hdif{7:50:20}{5:50:20}\par
+d) \hdif{7:50:10}{6:50:20}\par
+e) \hdif{20:00:00}{19:59:15}\par
+f) \hdif{17:13:15}{14:12:45}|
+\end{exercice}\idx*[|)]{nombre}\xA7*\hdif[|)]\tidx*[|)]{ifnum}%
+
+\chapter{Une premi\xE8re r\xE9cursivit\xE9}\idx*[|(]{r\xE9cursivit\xE9}
+Le moment est venu de se jeter dans le grand bain de la r\xE9cursivit\xE9 ! En effet, nous en savons assez pour sortir de la programmation lin\xE9aire et passer au stade suivant.
+
+La d\xE9finition la plus commun\xE9ment admise, m\xEAme si elle est un peu laconique tient en ces mots : un algorithme est r\xE9cursif\idx*{r\xE9cursivit\xE9} s'il s'appelle lui-m\xEAme. Dans le cas d'une macro, cela signifie qu'une macro est r\xE9cursive si elle s'appelle elle-m\xEAme, que ce soit directement ou par le truchement d'autres macros interm\xE9diaires. On comprend bien que cela implique qu'une \emph{boucle} se met en place, c'est-\xE0-dire qu'une portion de code sera lue plusieurs fois.
+
+Pour prendre une analogie, nous mettrions en place une \idx{r\xE9cursivit\xE9} si, pour parcourir un trajet rectiligne de A vers B, nous nous fixions comme r\xE8gle de reculer de 10 m\xE8tres \xE0 chaque fois que nous passons sur un point pr\xE9cis C du parcours. Le simple bon sens montre que nous n'arriverons jamais \xE0 la fin du parcours. En effet, nous serions prisonniers d'une \idx{boucle infinie}, condamn\xE9s \xE0 parcourir \xE9ternellement la m\xEAme portion de 10 m\xE8tres ! Pour \xE9viter cet \xE9cueil, il faudrait une r\xE8gle suppl\xE9mentaire, appel\xE9e \xAB\idx{point d'arr\xEAt}\xBB qui permet de sortir de cette boucle. Par exemple
+
+\begin{itemize}
+	\item ne rebrousser chemin si le nombre de fois que l'on a vu le point C est inf\xE9rieur \xE0 20;
+	\item au point C, continuer sans rebrousser chemin si l'on march\xE9 plus d'une heure;
+	\item ne rebrousser chemin au point C que si l'on a parcouru moins de \numprint[km]{1}.
+\end{itemize}
+
+Il en va de m\xEAme en informatique. Une r\xE9cursivit\xE9 \emph{doit} comporter un \idx{point d'arr\xEAt} sans quoi elle devient une \idx{boucle infinie}. Un point \idx{point d'arr\xEAt} est un test sur un param\xE8tre qui \xE9volue avec les it\xE9rations de telle sorte qu'\xE0 un moment, ce test change d'\xE9tat et valide la sortie de boucle.
+\grandsaut
+
+Ne nous lan\xE7ons pas dans une macro de grande ampleur et dans un premier temps, restons tout de m\xEAme modestes. Fixons-nous comme objectif de programmer une commande \xA7\ncar[|(] qui admet 2 arguments, le premier est un nombre positif $n$ et le second un caract\xE8re. Le but de cette macro sera d'afficher le caract\xE8re $n$ fois.
+
+Cette macro, effectuant un travail tr\xE8s simple, sera un pr\xE9texte pour envisager plusieurs m\xE9thodes de programmation.
+
+\subsubsection{Une premi\xE8re approche}
+Il suffit d'un peu de r\xE9flexion pour b\xE2tir un algorithme effectuant l'action voulue. L'approche la plus naturelle fait appel \xE0 une variable qui, dans le monde de \TeX{} sera un compteur :
+
+\begin{algo}
+	\item assigner 0 au \idx{compteur};
+	\item si le compteur est strictement inf\xE9rieur \xE0 $n$
+	\begin{algo}
+	\item afficher le caract\xE8re;
+	\item incr\xE9menter le compteur de 1;
+	\item retourner en 2;
+	\end{algo}
+	\item fin de l'algorithme
+\end{algo}
+
+Comment s'y prendre pour coder un tel algorithme en \TeX{}? Tout d'abord, nous voyons que le code correspondant au point 2 est parcouru plusieurs fois avec des valeurs diff\xE9rentes du compteur. Cette portion de code sera donc n\xE9cessairement \emph{r\xE9cursive}. Par cons\xE9quent, le point 1 sera d\xE9volu \xE0 une macro qui initialisera le compteur \xE0 0 et passera la main \xE0 une deuxi\xE8me macro, amen\xE9e \xE0 s'appeler elle-m\xEAme. Une macro qui proc\xE8de \xE0 des initialisations et passe la main \xE0 la \emph{vraie} macro principale s'appelle une macro \xABchapeau\xBB\idx*{macro chapeau}. D\xE9cidons de nommer la macro chapeau \verb|\ncar| et la macro r\xE9cursive \verb|\ncar at i|. Voici l'algorithme pr\xE9c\xE9dent pr\xE9sent\xE9 sous une forme d'un \emph{\idx{pseudocode}}, plus proche de la syntaxe avec laquelle on r\xE9dige un programme sans toutefois s'encombrer des subtilit\xE9s syntaxiques :
+
+\begingroup
+\numalgofalse
+\def\algoleftskip{.1\hsize}
+\def\algorightskip{.1\hsize}\label{algo1}
+\algorithm[\#]{Afficher $n$ fois un caract\xE8re}/
+macro ~ncar~#1#2
+	ii:=0% initialise le compteur \xE0 0
+	val at max:=#1% stocke la valeur maximale
+	car at save:=#2% stocke le caract\xE8re \xE0 afficher
+	~ncar at i~% appeler la macro r\xE9cursive
+~fin~\medskip
+macro ~ncar at i~
+	~si~ ii < val at max% si la valeur maxi n'est pas atteinte
+		afficher car at save
+		ii:=ii + 1% incr\xE9menter le compteur
+		ncar at i% recommencer
+	~finsi~
+~fin~/
+\endgroup
+
+Il est utile de remarquer que la boucle mise en place dans la macro \verb|ncar at i| est de type \xAB tant que\xBB. En effet, dans un pseudocode adapt\xE9 \xE0 un langage de plus haut niveau que ne l'est \TeX\footnote{Le format \LaTeX{} fournit une macro \texttt{\string\@whilenum} qui est un \xAB tant que \xBB o\xF9 le test fait est une comparaison sur des entiers.}, on aurait pu \xE9crire :
+
+\begingroup
+\numalgofalse
+\def\algoleftskip{.1\hsize}
+\def\algorightskip{.1\hsize}
+\algorithm[\#]{Macro ncar at i}/
+macro ~ncar at i~
+	~tant que~ ii < val at max% tant que la valeur maxi n'est pas atteinte
+		afficher car at save
+		ii:=ii + 1% incr\xE9menter le compteur
+	~fin tant que~
+~fin~/
+\endgroup
+
+Il suffit maintenant de traduire en \TeX{} le premier \idx{pseudocode}, plus proche du niveau de \TeX{} que ne l'est le second :
+
+\showcode/\newcount\ii\xA4\idx*\newcount\xA4
+\catcode`\@=11
+\def\ncar#1#2{%
+    \ii=0 % initialise le compteur \xE0 0
+    \def\val at max{#1}% stocke la valeur maximale
+    \def\car at save{#2}% stocke le caract\xE8re \xE0 afficher
+    \ncar at i% appelle la macro r\xE9cursive
+}
+\def\ncar at i{%\xA4\tidx*{ifnum}\xA4
+  \ifnum\ii<\val at max% si la valeur maxi n'est pas atteinte
+    \car at save% afficher le caract\xE8re
+    \advance\ii 1 % incr\xE9menter le compteur\xA4\idx*\advance\xA4
+    \ncar at i% recommencer\xA4\defline\aaa\xA4
+  \fi
+}
+\catcode`\@=12
+\ncar{7}{*}\par
+\ncar{13}W\par
+\ncar{10}{foobar }/\idx*[|)]{compteur}
+
+Cela fonctionne comme attendu, et m\xEAme au-del\xE0 puisque le code \xE0 reproduire est stock\xE9 dans une macro et donc, ce code peut \xEAtre constitu\xE9 de plusieurs caract\xE8res et pourrait aussi bien contenir des s\xE9quences de contr\xF4le. Ce code comporte n\xE9anmoins un d\xE9faut : la r\xE9cursivit\xE9 mise en place n'est pas terminale!
+
+\begin{regle}
+Une \idx[!terminale]{r\xE9cursivit\xE9} est terminale lorsque rien n'est laiss\xE9 sur la pile lors de l'appel r\xE9cursif.
+
+Pratiquement, la r\xE9cursivit\xE9 est terminale si l'appel r\xE9cursif intervient \emph{en dernier} dans le code de la macro qui s'appelle elle-m\xEAme ou intervient apr\xE8s avoir supprim\xE9 par d\xE9veloppement tout ce qui se trouve apr\xE8s cet appel.
+\end{regle}
+
+Ici ce n'est pas le cas puisque lorsque la macro \verb-\ncar at i- s'appelle elle m\xEAme \xE0 la ligne \no\aaa{}, il reste encore le \tidx{fi} avant la fin du code de la macro. Ce \tidx{fi}, r\xE9sidu non encore r\xE9sorb\xE9 du test \tidx{ifnum}, va rester sur la pile pour \xEAtre lu plus tard. Par cons\xE9quent, dans les exemples ci-dessus, il y aura 7, 13 ou 10 \tidx{fi} qui vont s'accumuler sur la pile pour qu'apr\xE8s le dernier test (qui sera n\xE9gatif), ils soient tous lus ce qui provoquera leur disparition par d\xE9veloppement. Pour ne pas surcharger inutilement la pile de \TeX{}, il faut supprimer le \tidx{fi} \emph{avant} d'effectuer l'appel r\xE9cursif. Il suffit ici de placer un \idx\expandafter avant l'appel r\xE9cursif \verb-\ncar at i- pour 1-d\xE9velopper le \tidx{fi}.
+
+Mais il y a plus grave\ldots{} En plus de la r\xE9cursivit\xE9 non terminale\idx*{r\xE9cursivit\xE9!terminale}, le code donn\xE9 ci-dessus comporte une faute de programmation. Comme nous l'avons vu, lorsque \TeX{} lit le nombre qui suit le signe de comparaison \verb-<-, il d\xE9veloppe au maximum\idx*{d\xE9veloppement maximal} tout ce qu'il trouve jusqu'\xE0 trouver quelque chose qui ne peut entrer dans la composition d'un nombre. Il va donc d\xE9velopper \verb-\val at max- (dont le d\xE9veloppement est constitu\xE9 de chiffres) et va poursuivre en d\xE9veloppant \emph{aussi} \verb-\car at save-. Si jamais le d\xE9veloppement de \verb-\car at save- est un chiffre ou commence par un ou plusieurs chiffres, ceux-ci vont entrer dans la composition du nombre et, \xE9tant absorb\xE9s lors de cette lecture, ils ne seront plus disponibles pour l'affichage. Non seulement le test se fera sur une valeur fausse, mais un ou plusieurs caract\xE8res pr\xE9vus pour \xEAtre affich\xE9s seront captur\xE9s par le test et rendus indisponibles pour l'affichage.
+
+Nous pouvons en faire l'exp\xE9rience avec ce code :
+
+\showcode/\newcount\ii\xA4\idx*\newcount\xA4
+\catcode`\@=11
+\def\ncar#1#2{%
+    \ii=0 % initialise le compteur \xE0 0
+    \def\val at max{#1}% stocke la valeur maximale
+    \def\car at save{#2}% stocke le caract\xE8re \xE0 afficher
+    \ncar at i% appelle la macro r\xE9cursive
+}
+\def\ncar at i{%
+  \ifnum\ii<\val at max% si la valeur maxi n'est pas atteinte
+    \car at save% afficher le caract\xE8re
+    \advance\ii 1 % incr\xE9menter le compteur\xA4\idx*\advance\xA4
+    \ncar at i% recommencer
+  \fi
+}
+\catcode`\@=12
+\ncar{2}{3a}/
+
+Ici, le premier test qui est fait, alors que \verb|\ii| vaut 0, est :
+
+\centrecode-\ifnum\ii<23-
+
+\noindent o\xF9 le 2 est le d\xE9veloppement de \verb|\val at max| et le 3 est le d\xE9but de celui de \verb|\car at save|. Ce test est vrai et le restera jusqu'\xE0 ce que le compteur vaille 23. La macro \verb|\ncar at i| va donc s'appeler 23 fois, et le \xAB\verb|a|\xBB, qui stoppe la lecture du nombre, sera donc affich\xE9 23 fois.
+
+Pour \xE9viter que \TeX{} ne d\xE9veloppe trop loin, il \emph{faut} mettre un \idx\relax\footnote{On pourrait aussi mettre une macro qui se d\xE9veloppe en un espace puisqu'un espace stoppe la lecture du nombre et, contrairement \xE0 \idx\relax, est absorb\xE9 par cette lecture. On peut donc remplacer \idx\relax par \texttt{\string\space}.} apr\xE8s \verb-\val at max- pour stopper la lecture du nombre. La bonne fa\xE7on de coder la macro \verb-\ncar at i- est donc :
+
+\centrecode-\def\ncar at i{%
+  \ifnum\ii<\val at max\relax
+    \car at save
+    \advance\ii 1
+    \expandafter\ncar at i
+  \fi}-
+\grandsaut
+
+Voici maintenant deux autres variantes pour coder cette macro :
+
+\begin{enumerate}
+	\item on peut utiliser une macro auxiliaire \verb-\donext- qui sera \xE9gale, selon l'issue du test, aux instructions \xE0 effectuer s'il est positif et \xE0 \idx\relax sinon. La macro sera appel\xE9e apr\xE8s \xEAtre sorti des branches du test :
+
+\centrecode-\def\ncar at i{%
+	\ifnum\ii<\val at max\relax
+		\def\donext{\car at save \advance\ii 1 \ncar at i}%
+	\else
+		\let\donext\relax
+	\fi
+	\donext
+}-
+	\item une autre m\xE9thode, plus \xE9l\xE9gante et plus \xE9conome, car elle se passe d'une macro temporaire consisterait, selon l'issue du test, \xE0 lire l'argument entre accolades se trouvant juste apr\xE8s le \tidx{fi} ou \xE0 manger cet argument. Pour ces deux actions, on utilise les macros d\xE9j\xE0 d\xE9finies \xA7\identity et \xA7\gobone (voir page~\pageref{identity}) :
+
+\centrecode-\def\ncar at i{%
+	\ifnum\ii<\val at max\relax
+		\expandafter\identity% ex\xE9cute...\xA4\xA7*\identity\xA4
+	\else
+		\expandafter\gobone% ou mange...
+	\fi
+	{\car at save \advance\ii 1 \ncar at i}%... ce code
+}-
+\end{enumerate}
+
+\begin{exercice}
+Trouver un moyen pour programmer la macro \verb-\ncar{n}{<car>}- sans programmer aucune boucle ni aucune r\xE9cursivit\xE9.
+
+L'exercice est vraiment difficile et tient davantage lieu de curiosit\xE9 ou d'acrobatie \TeX nique que de vraie m\xE9thode.
+\solution
+Nous allons mettre \xE0 contribution la primitive \idx\romannumeral et utiliser une de ses propri\xE9t\xE9s : si un nombre est sup\xE9rieur \xE0 1000, alors cette macro produit un nombre en chiffres romains qui commence avec autant de fois le caract\xE8re \xAB\verb|m|\xBB (de catcode 12\idx*{catcode!12 (autre)}) qu'il y a de milliers dans le nombre pass\xE9 en argument :
+
+\showcode/a) \romannumeral 9600 \qquad b) \romannumeral 12000/
+
+Lorsque nous allons appeler la macro \verb-\ncar{#1}{#2}- il va suffire d'ajouter \xAB000\xBB apr\xE8s le nombre \verb-#1- pour obtenir \verb-#1- fois le caract\xE8re \xAB\verb|m|\xBB via la primitive \idx\romannumeral. Il ne nous restera plus qu'\xE0 \xAB transformer \xBB le caract\xE8re \xAB\verb|m|\xBB vers le caract\xE8re que nous souhaitons afficher. Nous avons d\xE9j\xE0 vu comment le faire \xE0 l'aide de \idx\lccode et la primitive \idx\lowercase :
+
+\showcode/\def\ncar#1#2{%
+	\begingroup\xA4\idx*\begingroup\idx*\lccode\xA4
+	\lccode`\m=`#2 % dans \lowercase, les "m" deviennent des "#2"
+	\lowercase\expandafter{\expandafter\endgroup\romannumeral#1000 }%\xA4\idx*\lowercase\idx*\endgroup\idx*\romannumeral\xA4
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{15}{\%}\qquad
+c) \ncar{10}{4}/
+
+Comme toutes les primitives devant \xEAtre suivies d'une accolade ouvrante, \idx\lowercase d\xE9veloppe au maximum\idx*{d\xE9veloppement maximal} tout ce qui se trouve entre elle et cette accolade. Le d\xE9veloppement d'un pont d'\idx[|etc]\expandafter\forbidindex\expandafter{} exploite ici cette propri\xE9t\xE9 pour propager le d\xE9veloppement et 1-d\xE9velopper \verb*-\romannumeral#1000 -. Ce d\xE9veloppement est \emph{n\xE9cessaire} car sans lui, l'argument de \idx\lowercase serait :
+
+\centrecode-\endgroup\romannumeral#1000 -
+
+\noindent et comme cet ensemble de tokens ne contient pas le token \xAB\verb|m|\xBB, \idx\lowercase n'aurait aucune action et ce code serait lu tel quel.
+
+Nous r\xE9pondons bien \xE0 l'\xE9nonc\xE9 de l'exercice, aucune r\xE9cursivit\xE9 ou boucle \emph{explicite} n'a \xE9t\xE9 utilis\xE9e. Il est \xE9vident qu'en coulisses, \TeX{} utilise une boucle lorsqu'il ex\xE9cute la primitive \idx\romannumeral.
+\end{exercice}
+
+\Qu elle que soit la m\xE9thode employ\xE9e pour parvenir \xE0 nos fins, aucune d'entre elles n'est \emph{purement d\xE9veloppable}. Si nous \xE9crivions
+
+\centrecode-\edef\foo{\ncar{3}{*}}-
+
+\noindent le texte de remplacement de \verb|\foo| ne serait pas \xAB\verb|***|\xBB.. La raison tient au fait que les textes de remplacements de \verb|\ncar| ou \verb|\ncar at i| contiennent des s\xE9quences de contr\xF4le non d\xE9veloppables :
+
+\begin{itemize}
+	\item un compteur \verb|\ii|;
+	\item la primitive \idx\def;
+	\item la primitive \idx\advance.
+\end{itemize}
+
+\subsubsection{Une approche purement d\xE9veloppable}
+Pour construire une macro purement d\xE9veloppable, il faut proscrire toutes les primitives non d\xE9veloppables contenues dans le code actuel : \idx\advance, \idx\relax, \idx\def et les appels aux compteurs. La question qui se pose naturellement est : \xAB sans compteur, comment compter \xBB ?
+
+Le r\xE9ponse tient dans la primitive de \idx\eTeX : \idx\numexpr. L'id\xE9e est de programmer \verb-\ncar- pour que cette macro s'appelle elle-m\xEAme en d\xE9cr\xE9mentant son premier argument avec \idx\numexpr; cet argument ira donc \emph{en d\xE9croissant} de la valeur maxi \xE0 0, alors que c'\xE9tait l'inverse pour les versions vues jusqu'alors. Le fait que \verb|\ncar| s'appelle directement elle-m\xEAme rend inutile toute macro auxiliaire. Voici ce que devient l'algorithme, toujours du type \xAB tant que \xBB, qui tend vers une extr\xEAme simplicit\xE9 :
+
+\begingroup
+\numalgofalse
+\def\algoleftskip{.1\hsize}
+\def\algorightskip{.1\hsize}
+\algorithm[\#,\{,\}]{D\xE9cr\xE9menter le 1\ier{} argument}/macro ~ncar~#1#2
+		~si~ #1 > 0
+			afficher #2
+			appeler ~ncar~{#1-1}{#2}
+		~fin si~
+~fin~/
+\endgroup
+
+Du c\xF4t\xE9 de \TeX{}, l'appel r\xE9cursif prendra la forme suivante :
+
+\centrecode/\exparg\ncar at i{\number\numexpr#1-1}{#2}/
+
+\noindent o\xF9 \xA7\exparg 1-d\xE9veloppe \idx\number qui lance \idx\numexpr qui \xE0 son tour, effectue le calcul \verb/#1-1/. Tout cela donnera un argument de \xAB5\xBB si \verb-#1- vaut \xAB6\xBB. Regardons le code fonctionner sur un exemple :
+
+\showcode/\def\ncar#1#2{%
+  \ifnum#1>0 % <- espace apr\xE8s le "0"
+    #2% affiche le caract\xE8re
+    \exparg\ncar{\number\numexpr#1-1}{#2}% appel r\xE9cursif\xA4\idx*\number\idx*\numexpr\xA7*\exparg\xA4
+  \fi
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}{7}}\meaning\foo/
+
+La premi\xE8re chose importante \xE0 noter que le 0 est suivi d'un espace ce qui stoppe la lecture du nombre et qui met \xE0 l'\xE9cart \verb-#2-, m\xEAme s'il commence par des chiffres. La seconde remarque est que cette r\xE9cursivit\xE9 n'est pas terminale\idx*{r\xE9cursivit\xE9!terminale} puisque le \tidx{fi} n'est pas mang\xE9 avant l'appel r\xE9cursif. Comme cela a \xE9t\xE9 vu pr\xE9c\xE9demment, les macros \xA7\identity et \xA7\gobone r\xE8glent ce probl\xE8me :
+
+\showcode/\def\ncar#1#2{%
+	\ifnum#1>0 \expandafter\identity% si #1>0 ex\xE9cuter...\xA4\xA7*\identity\xA4
+	\else      \expandafter\gobone% ...sinon manger\xA4\xA7*\gobone\xA4
+	\fi% ce qui est entre ces accolades :
+		{#2% afficher le caract\xE8re
+		\exparg\ncar{\number\numexpr#1-1}{#2}% appel r\xE9cursif\xA4\idx*\number\idx*\numexpr\xA7*\exparg\xA4
+		}%
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo/
+
+\subsubsection{Jouer avec le \texttt{\char`\\fi}}
+Une autre ruse de \TeX pert consiste \xE0 \xE9crire une macro \xE0 argument d\xE9limit\xE9 qui \emph{inverse} l'ordre d'un \verb-<code>- quelconque et du prochain \tidx{fi}, sous r\xE9serve que le \verb|<code>| ne contienne pas un \tidx{fi} :
+
+\centrecode-\long\def\antefi#1\fi{\fi#1}-\xA7*\antefi
+
+\noindent La macro \xA7\antefi lit tout le code \verb-#1- jusqu'au prochain \tidx{fi} qui sert de d\xE9limiteur. Ce \tidx{fi}, partie int\xE9grante de la macro, n'est pas ex\xE9cut\xE9 et n'est donc pas pas pris en compte par le compteur interne de \tidx{fi}. Ce n'est que lorsque \xA7\antefi se d\xE9veloppera que le \tidx{fi}, token rendu en premier, marquera pour \TeX{} la fin de la port\xE9e du test.
+
+\showcode/\long\def\antefi#1\fi{\fi#1}\xA4\xA7*\antefi\idx*\long\xA4
+\def\ncar#1#2{%
+	\ifnum#1>0
+		\antefi% comme si le \fi \xE9tait "d\xE9plac\xE9" ici\xA4\xA7*\antefi\xA4
+		#2% affiche le caract\xE8re
+		\exparg\ncar{\number\numexpr#1-1}{#2}% appel r\xE9cursif\xA4\idx*\number\idx*\numexpr\xA4
+	\fi
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo/
+
+La pr\xE9sence d'un \tidx{else} provoquerait une erreur si le \xA7\antefi se trouvait avant le \tidx{else}. Dans ce cas, le \xA7\antefi se d\xE9velopperait en \tidx{fi} suivi d'un code \verb|#1| contenant un \tidx{else} qui du coup, se retrouverait orphelin, en dehors du territoire du test. En revanche, \xA7\antefi fonctionne bien dans la branche \tidx{else}\linebreak[1]\verb-...-\tidx{fi} d'un test.
+
+\begin{exercice}
+Comment peut-on modifier la d\xE9finition de \xA7\antefi pour que l'astuce fonctionne aussi bien avec la pr\xE9sence d'un \tidx{else} que sans ?
+\solution
+Nous pouvons d\xE9finir comme argument \emph{non d\xE9limit\xE9} le code \xE0 mettre apr\xE8s le \tidx{fi}. Appelons \xA7\afterfi cette macro qui aura pour mission de placer apr\xE8s le \tidx{fi} son argument :
+
+\centrecode/\long\def\afterfi#1#2\fi{#2\fi#1}/
+
+\noindent De cette fa\xE7on, si l'argument d\xE9limit\xE9 \verb-#2- contient un \tidx{else}, ce \tidx{else} est recopi\xE9 tel quel et se trouve devant le \tidx{fi} et donc n'occasionnera aucune erreur de compilation.
+
+\showcode/\long\def\afterfi#1#2\fi{#2\fi#1}\xA4\xA7*\afterfi\idx*\long\xA4
+\def\ncar#1#2{%
+	\ifnum#1>0
+		\afterfi{\exparg\ncar{\number\numexpr#1-1}{#2}}% <- argument renvoy\xE9 apr\xE8s le \fi\xA4\idx*\number\idx*\numexpr\xA7*\afterfi\xA4
+		#2% <- ceci reste avant le \fi
+	\fi
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo/
+\end{exercice}
+
+\subsubsection{Une solution avec \texttt{\char`\\expandafter}}
+Si nous \xE9tions \xE9tait \emph{certains} que l'argument \verb|#2| \xE9tait compos\xE9 d'un unique token, nous pourrions nous passer de \xA7\antefi ou \xA7\afterfi et sauter ce token pour aller d\xE9velopper le \tidx{fi} et rendre la r\xE9cursivit\xE9 terminale\idx*{r\xE9cursivit\xE9!terminale}. Il suffirait de propager le d\xE9veloppement avec des \idx\expandafter :
+
+\centrecode/\def\ncar#1#2{%
+  \ifnum#1>0%
+    #2%
+    \expandafter\ncar\expandafter{\number\numexpr#1-1\expandafter}%
+    \expandafter{\expandafter#2\expandafter}%
+  \fi
+}/
+
+Mais l'appel \verb|\ncar{5}{foobar}| ne serait pas une r\xE9cursivit\xE9 terminale\idx*{r\xE9cursivit\xE9!terminale} puisque dans
+
+\centrecode/{\expandafter foobar\expandafter}/
+
+\noindent le pont d'\idx\expandafter est tr\xE8s insuffisant pour sauter tous les tokens de \xAB foobar \xBB. Si nous voulons nous passer de \xA7\antefi, ce qu'il y a de mieux \xE0 faire est de mettre l'argument \verb|{#2}| apr\xE8s le \tidx{fi}. Si le test est faux, il faudra manger cet argument avec \xA7\gobone et s'il est vrai, \verb|{#2}| reste en place et devient le 2\ieme{} argument de \xA7\ncar. Pour cela, l'astuce consiste \xE0 exploiter le fait que la primitive \idx\numexpr engage un d\xE9veloppement maximal. Il suffit donc de placer un \idx\expandafter \xE0 la fin de cette zone pour d\xE9velopper (et donc faire disparaitre) la branche \verb|\else...\fi| :
+
+\showcode/\def\ncar#1#2{%
+  \ifnum#1>0
+    #2% afficher le caract\xE8re
+    \expandafter\ncar\expandafter% le pont d'\expandafter lance \number et \numexpr
+		{\number\numexpr#1-1\expandafter}% le dernier \expandafter mange "\else...\fi"\xA4\idx*\number\idx*\numexpr\xA4
+  \else
+    \expandafter\gobone% si le test est faux, manger {#2} ci-dessous\xA4\xA7*\gobone\xA4
+  \fi{#2}%
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo/
+
+\subsubsection{D\xE9finir une sous-macro}
+Examinons une derni\xE8re m\xE9thode pour construire une r\xE9cursivit\xE9 terminale\idx*{r\xE9cursivit\xE9!terminale}. \xC0 l'int\xE9rieur de la macro \verb-\ncar-, nous allons d\xE9finir une \xAB sous-macro \xBB nomm\xE9e \verb-\ncar at i- qui elle, n'admettra qu'un seul argument, le nombre not\xE9 \verb|i| qui compte les it\xE9rations. Gr\xE2ce \xE0 l'imbrication des macros, les arguments de la macro m\xE8re \verb-\ncar- seront accessibles dans le texte de remplacement de \idx{macro fille} \verb-\ncar at i-. Rappelons-nous que le token \verb-#- doit \xEAtre doubl\xE9 \xE0 chaque niveau d'imbrication de \verb|\def| pour distinguer les arguments de la macro m\xE8re de ceux de la macro fille.
+
+Nous compterons dans \emph{l'ordre croissant}, de 0 la valeur maxi.
+
+\showcode/\catcode`\@11
+\def\ncar#1#2{%
+	\def\ncar at i##1{%
+		\ifnum##1<#1 % si i < valeur maxi
+		#2% afficher le caract\xE8re
+		\exparg\ncar at i{\number\numexpr##1+1\expandafter}% puis recommencer avec i+1\xA4\idx*\number\idx*\numexpr\xA4
+		\fi% \fi mang\xE9 par le \expandafter en fin de zone de \numexpr
+	}%
+	\ncar at i{0}% commence avec la valeur "compteur" 0
+}
+\catcode`\@12
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \ncar{5}{X}/
+
+L'inconv\xE9nient de cette m\xE9thode est que la macro \verb-\ncar- n'est pas purement d\xE9veloppable puisque son texte de remplacement contient la primitive \idx\def\xA7\ncar[|)].
+
+\begin{exercice}\label{compte}\xA7*\compte[|(]%
+\xC9crire une macro \verb-\compte{<nombre>}- qui affiche les entiers de 1 \xE0 \verb-<nombre>-, s\xE9par\xE9s les uns des autres par une virgule et une espace. Si le \verb-<nombre>- est n\xE9gatif ou nul, aucun affichage ne sera produit.
+
+On \xE9crira un code non purement d\xE9veloppable utilisant un compteur et un code purement d\xE9veloppable. Dans tous les cas, la r\xE9cursivit\xE9 devra \xEAtre terminale.
+\solution
+Voici un code qui n'est pas purement d\xE9veloppable. Comme au premier exemple vu avec \verb-\ncar-, nous utilisons un compteur et nous stockons la valeur maximale dans la s\xE9quence de contr\xF4le \verb-\val at max-. 
+
+\showcode/\catcode`\@11 \newcount\compte at cnt\xA4\idx*\newcount\xA4
+\def\compte#1{%
+	\def\val at max{#1}\compte at cnt=0 % effectue les initialisations
+	\compte at i% appelle la macro principale
+}
+\def\compte at i{%
+	\ifnum\compte at cnt<\val at max% si compteur < valeur maxi
+		\advance\compte at cnt1 % incr\xE9menter le compteur\xA4\idx*\advance\xA4
+		\number\compte at cnt, % afficher le nombre, la virgule et l'espace\xA4\idx*\number\xA4
+		\expandafter\compte at i %recommencer
+	\fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \compte{2}/
+
+Le probl\xE8me saute aux yeux et r\xE9v\xE8le une erreur de programmation : la virgule et l'espace sont aussi affich\xE9s apr\xE8s le dernier nombre, ce qui ne devrait pas \xEAtre le cas.
+
+La m\xE9thode la plus imm\xE9diate est de tester \xE0 l'int\xE9rieur du test principal si, apr\xE8s incr\xE9mentation, \verb-\compte at cnt- est inf\xE9rieur \xE0 \verb-\val at max- et si tel est le cas, afficher \xAB\verb*-, -\xBB. Voici donc le code corrig\xE9 :
+
+\showcode/\catcode`\@11 \newcount\compte at cnt\xA4\idx*\newcount\xA4
+\def\compte#1{\def\val at max{#1}\compte at cnt=0 \compte at i}
+\def\compte at i{%
+	\ifnum\compte at cnt<\val at max\relax
+		\advance\compte at cnt1 \xA4\idx*\advance\xA4
+		\number\compte at cnt
+		\ifnum\compte at cnt<\val at max , \fi% afficher ", " si le maxi n'est pas atteint\xA4\defline\aaa\xA4
+		\expandafter\compte at i
+	\fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b)\compte{-4}\qquad
+c) \compte{2}/
+
+Bien qu'il fonctionne parfaitement, ce code n'est pas satisfaisant parce que le test de la ligne \no\aaa{} est fait \xE0 chaque it\xE9ration. Certes, le ralentissement qu'il occasionne \xE0 chaque fois est insignifiant, mais il est r\xE9el et il se cumule au fur et \xE0 mesure des appels. Un programmeur rigoureux optimiserait ce code.
+
+Essayons de supprimer ce test. Nous allons tout d'abord rajouter un test dans la macro \verb-\compte- pour tester si son argument est strictement positif, seul cas o\xF9 quelque chose sera affich\xE9. Ce test ne sera donc fait qu'une fois. Dans le cas o\xF9 il est positif, la macro r\xE9cursive \verb|\coompte at i| sera appel\xE9e et elle produira l'affichage en deux \xE9tapes :
+
+\begin{itemize}
+	\item la valeur du compteur sera affich\xE9e;
+	\item le test d\xE9cidant si la macro s'appelle elle-m\xEAme sera fait et s'il est positif, cela signifie qu'il reste encore des valeurs \xE0 afficher. La virgule et l'espace seront donc affich\xE9s avant que le compteur ne soit incr\xE9ment\xE9 et l'appel r\xE9cursif ne soit ex\xE9cut\xE9.
+\end{itemize}
+
+\showcode/\catcode`\@11 \newcount\compte at cnt\xA4\idx*\newcount\xA4
+\def\compte#1{%
+  \ifnum#1>0 % ne faire quelque chose que si l'argument est positif
+    \def\val at max{#1}\compte at cnt=1 % faire les initialisations
+    \expandafter\compte at i% appeller la macro r\xE9crusive
+  \fi
+}
+\def\compte at i{%
+  \number\compte at cnt\relax % afficher le nombre
+  \ifnum\compte at cnt<\val at max\relax % si valeur maxi n'est pas atteinte
+    , % afficher la virgule et l'espace
+    \advance\compte at cnt1 % incr\xE9menter le compteur\xA4\idx*\advance\xA4
+    \expandafter\compte at i % recommencer
+  \fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \compte{2}/
+
+Passons maintenant \xE0 une solution purement d\xE9veloppable dans laquelle, pour compter les it\xE9rations, nous allons utiliser la primitive \idx\numexpr. Nous allons traduire l'algorithme vu ci-dessus de fa\xE7on \xE0 nous passer de compteur. Il suffit de passer \xE0 la macro \verb-\compte at i- deux arguments, l'un qui contient la valeur \xE0 afficher (et qui compte les it\xE9rations \xE0 partir de 1) et l'autre la valeur maximale qui est l'argument \verb-#1- de \verb-\compte-. Comme vu dans un exemple pr\xE9c\xE9dent, nous rendons cette fois-ci la r\xE9cursivit\xE9 terminale\idx*{r\xE9cursivit\xE9!terminale} en mettant le code \emph{entier} contenant l'appel r\xE9cursif dans un argument apr\xE8s le \tidx{fi} : cet argument sera lu tel quel avec \xA7\identity si le test est positif et sera mang\xE9 avec \xA7\gobone dans le cas contraire.
+
+\showcode/\catcode`\@11
+\def\compte#1{%
+	\ifnum#1>\z@% ne faire quelque chose que si #1 > 0\xA4\idx*\z@\xA4
+		\antefi\compte at i{1}{#1}%\xA4\xA7*\antefi\xA4
+	\fi
+}
+
+\def\compte at i#1#2{%
+	#1% afficher le nombre
+	\ifnum#1<#2 % si le maxi n'est pas atteint
+		\expandafter\identity% ex\xE9cuter...\xA4\xA7*\identity\xA4
+	\else
+		\expandafter\gobone% sinon, manger...\xA4\xA7*\gobone\xA4
+	\fi% le code entre accolades ci-dessous
+		{, % afficher la virgule et l'espace
+		\exparg\compte at i{\number\numexpr#1+1}{#2}% appel r\xE9cursif\xA4\idx*\number\idx*\numexpr\xA7*\exparg\xA4
+		}%
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \edef\foo{\compte{2}}\meaning\foo/
+
+Une variante plus concise aurait \xE9t\xE9 possible en utilisant \xA7\antefi dans la macro auxiliaire :
+
+\showcode/\catcode`\@11
+\def\compte#1{%
+	\ifnum#1>\z@% ne faire quelque chose que si #1 > 0\xA4\idx*\z@\xA4
+		\antefi\compte at i{1}{#1}%\xA4\xA7*\antefi\xA4
+	\fi
+}
+
+\def\compte at i#1#2{%
+  #1% afficher le nombre
+  \ifnum#1<#2 % si le maxi n'est pas atteint
+    \antefi% d\xE9place le \fi ici\xA4\xA7*\antefi\xA4
+    , % affiche la virgule et l'espace
+    \exparg\compte at i{\number\numexpr#1+1}{#2}% appel r\xE9cursif\xA4\idx*\number\idx*\numexpr\xA7*\exparg\xA4
+  \fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \edef\foo{\compte{2}}\meaning\foo/
+\xA7*\compte[|)]\end{exercice}
+
+Il faut tirer une le\xE7on de ce chapitre. La programmation de macros r\xE9cursives purement d\xE9veloppables, disqualifiant de fait tout stockage d'information via un compteur, \idx\def ou \idx\toks, oblige \xE0 transmettre ces informations sous forme d'arguments. Il devient donc n\xE9cessaire de fournir \xE0 chaque it\xE9ration tous les arguments n\xE9cessaires au fonctionnement de la macro m\xEAme si parfois, des arguments invariables (comme la valeur maximale \verb|#2| ci-dessus) doivent \xEAtre lus \xE0 chaque fois.
+
+Rendre une macro r\xE9cursive purement d\xE9veloppable est l'assurance qu'elle va fonctionner comme on l'attend dans tous les cas et \xE0 ce titre, tend \xE0 devenir le Graal que certains recherchent \xE0 tout prix. Il est cependant bon de garder \xE0 l'esprit que la facilit\xE9 et la s\xE9curit\xE9 que l'on gagne d'un c\xF4t\xE9 cachent une certaine lourdeur dans les m\xE9canismes mis en jeu dans sa programmation. Les contorsions que l'on doit faire notamment au niveau des arguments pour rendre une macro purement d\xE9veloppable impliquent g\xE9n\xE9ralement une programmation beaucoup plus d\xE9licate que si elle ne n'\xE9tait pas.\idx*[|)]{r\xE9cursivit\xE9}
+
+\chapter{Une boucle \xAB for \xBB}\xA7*\for[|(]
+\label{for}Nous savons \xE0 pr\xE9sent suffisamment de choses pour programmer une structure de contr\xF4le de type \xAB \verb|for| \xBB o\xF9 une \xAB variable \xBB --~une macro en r\xE9alit\xE9~-- va prendre les valeurs enti\xE8res successives entre deux entiers $n_1$ et $n_2$. Fixons-nous par exemple la syntaxe sera la suivante :
+
+\begin{centrage}
+	\small\verb|\for\<macro>=|$n_1$\verb| to |$n_2$\verb|\do{<code>|
+\end{centrage}
+
+\noindent o\xF9 le \verb-<code>- pourra contenir la \verb-\<macro- qui tient lieu de variable et qui prend successivement toutes les valeurs de $n_1$ \xE0 $n_2$. Compte tenu de sa syntaxe, il est bien \xE9vident que la macro \verb-\for- doit avoir un texte de param\xE8tre contenant des arguments d\xE9limit\xE9s par \xAB=\xBB, \xAB\verb|to|\xBB et par \xAB\verb-\do-\xBB.
+
+\subsubsection{Une premi\xE8re version}
+Voici un premier jet, assez intuitif :
+
+\showcode/\catcode`\@11
+\def\for#1=#2to#3\do#4{% #1=\<macro>   #2=n1   #3=n2   #4=<code>
+	\def#1{#2}% initialise la \<macro> \xE0 l'entier n1\xA4\defline\aaa\xA4
+	\def\val at max{#3}% stocke n2
+	\def\loop at code{#4}% stocke le <code>
+	\for at i#1% appelle la macro r\xE9cursive et passe la \<macro> en argument
+}
+\def\for at i#1{%
+	\unless\ifnum#1>\val at max\relax% tant que la \<macro> est <= n2\xA4\tidx*{unless}\xA4
+		\loop at code% effectue le code pr\xE9c\xE9demment sauvegard\xE9
+		\edef#1{\number\numexpr#1+1}% incr\xE9menter la \<macro>\xA4\idx*\number\idx*\numexpr\xA4
+		\expandafter\for at i\expandafter#1% et recommencer apr\xE8s avoir mang\xE9 le \fi
+	\fi
+}
+\catcode`\@=12
+\for\ii=1to5\do{Maintenant \string\ii\ vaut : \ii.\endgraf}\medbreak\xA4\idx*\medbreak\idx*\string\xA4
+"\for\ii=1to0\do{A}"\medbreak% boucle parcourue 0 fois
+"\for\ii=1to1\do{A}"\medbreak% boucle parcourue 1 fois\xA4\idx*\medbreak\xA4
+\for\ii = 0 to 10 \do {[\ii]}.\xA4\defline\bbb\xA4/
+
+Remarquons tout d'abord que la s\xE9quence de contr\xF4le \idx\do n'est jamais d\xE9finie et peu importe qu'elle le soit\footnote{Comme nous l'avons vu, elle est bel et bien d\xE9finie dans plain-\TeX{} notamment pour seconder la macro \idx\dospecials.} : elle ne sert que de d\xE9limiteur \xE0 l'argument \verb-#3- de la macro \verb-\for-.
+
+\xC0 la ligne \no\aaa, l'argument \verb|#2|, qui est l'entier $n_1$, est assign\xE9 \xE0 \verb-#1- qui est la \verb|\<macro>|. C'est une mauvaise id\xE9e si on laisse des espaces --~toujours utiles pour la lisibilit\xE9~-- comme c'est le cas \xE0 l'appel de la ligne \no\bbb. Dans ce cas, lors de la premi\xE8re it\xE9ration, \verb-#1- a comme texte de remplacement \xAB\verb*- 0 -\xBB. Pour se pr\xE9munir de cet inconv\xE9nient, il aurait fallu \xE9crire \xE0 la ligne \no\aaa{}
+
+\centrecode-\edef#1{\number\numexpr#2\relax}-
+
+\noindent et ainsi tirer parti du fait que non seulement \idx\numexpr \xE9value l'\xE9ventuelle expression arithm\xE9tique \verb|#1|, mais le fait en \emph{ignorant les espaces}. La m\xEAme m\xE9thode doit \xEAtre utilis\xE9e pour stocker l'entier $n_2$ dans \verb|\val at max|.
+
+Plut\xF4t que de d\xE9finir une macro auxiliaire r\xE9cursive \verb-\for at i- \emph{\xE0 l'ext\xE9rieur} de la macro principale comme c'est le cas ici, nous avons tout \xE0 gagner \xE0 la d\xE9finir \xE0 l'int\xE9rieur en tant que \xAB \idx{macro fille}\xBB. De cette fa\xE7on, tous les arguments de la macro chapeau sont accessibles. Nous \xE9conomisons donc la macro \verb-\loop at code-.
+
+Remarquons enfin que la macro \verb-\for- n'\xE9tait pas d\xE9clar\xE9e \idx\long, interdisant donc la primitive \idx\par dans ses arguments. Ceci explique pourquoi il faut utiliser \idx\endgraf (une macro \idx\let-\xE9gale \xE0 \idx\par) pour provoquer la fin du paragraphe.
+
+\showcode/\catcode`\@11
+\long\def\for#1=#2to#3\do#4{%\xA4\xA7*\for\idx*\long\xA4
+	\def\for at i{%
+		\unless\ifnum#1>\val at max\relax% tant que la \<macro> <= n2\xA4\tidx*{unless}\xA4
+			#4% code \xE0 ex\xE9cuter
+			\edef#1{\number\numexpr#1+1}% incr\xE9menter \<macro>\xA4\idx*\number\idx*\numexpr\xA4
+			\expandafter\for at i% et recommencer apr\xE8s avoir mang\xE9 le \fi
+		\fi
+	}%
+	\edef#1{\number\numexpr#2\relax}% initialise la variable \xE0 n1
+	\edef\val at max{\number\numexpr#3\relax}% stocke n2
+	\for at i% appelle la sous-macro r\xE9cursive
+}
+\catcode`\@=12
+\for\ii = 1 to 5 \do {Maintenant \string\ii\ vaut : \ii.\par}\medbreak\xA4\idx*\medbreak\idx*\string\xA4
+"\for\ii=1to0\do{A}"\medbreak% boucle parcourue 0 fois
+"\for\ii=1to1\do{A}"\medbreak% boucle parcourue 1 fois\xA4\idx*\medbreak\xA4
+\for\ii = 0 to 10 \do {[\ii]}./
+
+\subsubsection{Mise en place d'un incr\xE9ment}
+En l'\xE9tat actuel, la macro \verb-\for- incr\xE9mente sa \xAB variable \xBB de 1 \xE0 chaque it\xE9ration. Comment s'y prendre pour que cet incr\xE9ment puisse \xEAtre sp\xE9cifi\xE9 par l'utilisateur ce qui constituerait en quelque sorte un argument \xAB optionnel \xBB? Il est naturel de penser \xE0 cette syntaxe :
+
+\begin{centrage}
+	\small\verb|\for\<macro>=|$n_1$\verb| to |$n_2$ \verb|\do| $i$ \verb|{<code>}|
+\end{centrage}
+
+Nous allons modifier la macro \verb-\for- pour que l'incr\xE9ment $i$, qui est un entier sign\xE9, soit pris en compte. Si celui-ci n'est pas sp\xE9cifi\xE9, il sera pris \xE9gal \xE0 $1$ si $n_1<n_2$ et \xE0 $-1$ sinon. L'exercice est difficile, d'autant que nous ne savons pas encore tester si un argument est vide, il faudra donc trouver une autre m\xE9thode !
+
+Il faut d\xE9j\xE0 modifier le texte de param\xE8tre de la macro \verb-\for- pour qu'elle prenne un 4\ieme{} argument apr\xE8s le \verb-\do-, suivi ensuite du 5\ieme{} qui sera le code \xE0 ex\xE9cuter \xE0 chaque it\xE9ration. Ce serait une erreur que de la d\xE9finir ainsi :
+
+\centrecode-\def\for#1=#2to#3\do#4#5{...}-
+
+\noindent Le probl\xE8me avec cette d\xE9finition est que \TeX{} va toujours lire \emph{deux arguments} apr\xE8s le \verb-\do- ! Et si nous omettons l'argument optionnel, \verb-#4- va devenir le \verb-<code>- et \verb-#5- sera l'argument suivant, non destin\xE9 \xE0 \xEAtre lu par la macro ! Pour \xE9viter un tel m\xE9lange d'arguments, l'argument optionnel recevant $i$ \emph{doit} \xEAtre d\xE9limit\xE9 par l'accolade ouvrante\idx*{argument!d\xE9limit\xE9!par accolade} qui marque le d\xE9but du \verb-<code>-. Nous allons donc \xE9crire :
+
+\centrecode-\def\for#1=#2to#3\do#4#{...}-
+
+\noindent Ce faisant, \verb-#4- sera donc tout ce qui se trouve entre \verb-\do- et la prochaine accolade ouvrante, cet ensemble \xE9tant \xE9ventuellement vide. Mais en proc\xE9dant de cette fa\xE7on, l'argument \verb-{<code>}- ne sera pas encore lu. Il faudra appeler une macro auxiliaire charg\xE9e de lire le code devant \xEAtre ex\xE9cut\xE9 \xE0 chaque fois.
+
+L'autre probl\xE8me qui surgit est que l'argument \verb-#4- peut \xEAtre vide, ou \xE9gal \xE0 +4, -2 ou n'importe quel entier sign\xE9. Comment s'y prendre pour transformer cet argument en un nombre, m\xEAme s'il est vide ? L'astuce consiste \xE0 mettre un 0 devant cet argument et \xE9valuer le tout avec \idx\numexpr. Nous aurions donc :
+
+\centrecode-\edef\for at increment{\number\numexpr0#4\relax}-
+
+\noindent Par acquit de conscience, assurons-nous que cette astuce fonctionne. Voici les cas qui peuvent se pr\xE9senter :
+
+\begin{itemize}
+	\item si \verb-#4- est vide ou r\xE9duit \xE0 des espaces, alors le \xAB0\xBB ajout\xE9 sera \xE9valu\xE9 par \idx\numexpr et donc, \verb-\for at increment- vaudra 0 ;
+	\item si \verb-#4- vaut \xAB5\xBB alors, \xAB05\xBB sera \xE9valu\xE9 et nous obtiendrons 5;
+	\item si \verb-#4- vaut \xAB+4\xBB alors, \xAB0+4\xBB sera \xE9valu\xE9 et nous obtiendrons 4 ;
+	\item enfin, si \verb-#4- vaut \xAB-10\xBB alors, \xAB0-10\xBB sera \xE9valu\xE9 et vaudra -10.
+\end{itemize}
+
+Une fois ceci fait, si \verb-\for at increment- est nul, cela traduit une absence d'argument optionnel ou pire, un incr\xE9ment explicitement donn\xE9 \xE9gal \xE0 0 par l'utilisateur joueur ou inconscient! Dans ces cas, il suffit de le red\xE9finir \xE0 1 si $n1<n_2$ (soit si \verb-#2-${}<{}$\verb-#3-) et \xE0 $-1$ sinon.
+
+Passons \xE0 l'\xE9tape suivante : il faut v\xE9rifier que le signe de l'incr\xE9ment (lorsqu'il est explicitement \xE9crit) est \xAB compatible \xBB avec les valeurs de \verb-#2- et \verb-#3-. En effet, si \verb-#2- vaut 4, \verb-#3- vaut 10 et l'incr\xE9ment vaut $-2$, on comprend bien qu'additionner l'incr\xE9ment $-2$ \xE0 4 est une t\xE2che vaine. On n'arrivera jamais \xE0 10 et, apr\xE8s un \emph{tr\xE8s grand} nombre d'it\xE9rations, on va d\xE9passer la borne inf\xE9rieure $-2^{31}+1$ permise pour un nombre, provoquant \xE0 ce moment (ou m\xEAme avant) une erreur de compilation.
+
+Un peu d'analyse montre que l'incr\xE9ment est \xAB incompatible \xBB avec les bornes \verb-#2- et \verb-#3- si les entiers $\#3-\#2$ et \verb-\for at increment- sont de signes contraires, c'est-\xE0-dire lorsque le signe de l'expression arithm\xE9tique suivante est strictement n\xE9gatif :
+
+\centrecode/\for at increment*(#3-#2)/
+
+Voici le code :
+
+\showcode/\catcode`\@11
+\def\for#1=#2to#3\do#4#{%
+	\edef\for at increment{\number\numexpr0#4}% lit et normalise l'argument optionnel\xA4\defline\aaa\xA4
+	\ifnum\for at increment=\z@% s'il est nul,\xA4\idx*\z@\xA4
+		\edef\for at increment{% le red\xE9finir :
+			\ifnum\numexpr#3\relax<\numexpr#2\relax\xA4\defline\bbb\idx*\numexpr\xA4
+				-% ajoute un signe - si #3<#2
+			\fi
+			1% devant "1"
+		}% \for at increment vaut donc 1 ou -1
+	\fi
+	\ifnum\numexpr\for at increment*(#3-#2)\relax<\z@% si l'argument est incompatible\xA4\defline\ccc\idx*\z@\xA4
+		\expandafter\firstoftwo% ex\xE9cuter le 1er argument qui suit\xA4\xA7*\firstoftwo\xA4
+	\else
+		\expandafter\secondoftwo% sinon le second\xA4\xA7*\secondoftwo\xA4
+	\fi
+		{Incr\xE9ment incompatible !\gobone %\gobone mangera le <code> qui \xE0 lire\xA4\defline\ddd\xA4
+		}%
+		{\edef#1{\number\numexpr#2\relax}% initialise la \<macro>
+		\edef\cmp at sgn{\ifnum\for at increment<\z@<\else>\fi}% stocke "<" ou ">" pour plus tard\xA4\idx*\z@\xA4
+		\expandafter\for at i\expandafter#1\expandafter% appelle la macro r\xE9cursive
+			{\number\numexpr#3\relax}% et lui lui passe la \<macro> (#1) et n2 (#3)
+		}%
+}
+
+% #1 = \<macro>   #2 = n2
+\long\def\for at i#1#2#3{% l'argument #3 (le <code>) est lu \xE0 ce moment-l\xE0\xA4\idx*\long\xA4
+	\def\for at ii{%
+		\unless\ifnum#1\cmp at sgn#2\relax% tant que la \<macro> n'a pas d\xE9pass\xE9 n2\xA4\defline\fff\tidx*{unless}\xA4
+			#3% ex\xE9cute le <code>\xA4\defline\eee\xA4
+			\edef#1{\number\numexpr#1+\for at increment}% incr\xE9mente la \<macro>\xA4\idx*\number\idx*\numexpr\xA4
+			\expandafter\for at ii% recommence apr\xE8s avoir mang\xE9 le \fi
+		\fi
+	}%
+	\for at ii% appelle la sous-macro r\xE9cursive\xA4\defline\ggg\xA4
+}%
+\catcode`\@=12
+a) \for\ii = -4 to 7 \do{(\ii)}\par
+b) \for\jj = 20 to -50\do-10 {(\jj)}\par
+c) \for\xx = 8 to 185\do 20 {[\xx]}\par
+d) \for\yy = 0 to 10\do -2{(\yy)}\par
+e) "\for\ii = 1 to 0 \do1{XX}"\par
+f) "\for\ii = 1 to 1 \do{A}"\par% boucle parcourue 1 fois
+g) \for\ii=1to4\do{\for\jj=0to2\do{(\ii,\jj)}\par}% imbrication de boucles/
+
+Il est utile de reprendre ce code en d\xE9tail, car il comporte beaucoup d'astuces\ldots{} Laissons pour l'instant le cas g o\xF9 le probl\xE8me de l'imbrication de boucles sera r\xE9solu un peu plus loin.
+
+\xC0 la ligne \no\aaa{}, si le nombre \verb|\for at increment|, r\xE9sultat de l'\xE9valuation de \verb|0#4| est nul, cela signifie que l'argument optionnel \verb|#4| est absent ou \xE9gal \xE0 \verb|0|. Dans ce cas, la macro \verb|\for at increment| est red\xE9finie par un \idx\edef et un signe \xAB\verb|-|\xBB est ajout\xE9 si \verb|#3| est inf\xE9rieur \xE0 \verb|#2| (ligne \no\bbb) de telle sorte que \verb|\for at increment| contienne \verb|1| ou \verb|-1|.
+
+La ligne \no\ccc{} teste si \verb|\for at increment| est \xAB compatible \xBB avec les valeurs \verb|#2| et \verb|#3|. \xC0 l'aide des macros \xA7\firstoftwo et \xA7\secondoftwo, un des 2 arguments qui suit est ex\xE9cut\xE9 :
+
+\begin{itemize}
+	\item le premier argument se contente d'afficher \xAB Incr\xE9ment incompatible \xBB et appelle la macro \xA7\gobone qui mange le \verb-<code>- qui n'a pas encore \xE9t\xE9 lu ce qui termine tout le processus. Bien \xE9videmment, il est possible de ne rien afficher et se contenter de mettre \xA7\gobone dans le deuxi\xE8me argument;
+	\item le deuxi\xE8me argument d\xE9finit la s\xE9quence de contr\xF4le \verb-\cmp at sgn- pour que son texte de remplacement soit \xAB\verb-<-\xBB si l'incr\xE9ment est n\xE9gatif et \xAB\verb->-\xBB sinon. Ce signe sera utilis\xE9 dans un test plus tard. Il ne reste plus ensuite qu'\xE0 appeler la macro auxiliaire \verb-\for at i- en lui passant la \verb|\<macro>| (argument \verb-#1-) et l'entier $n_2$ (argument \verb-#3-) pr\xE9alablement \xE9valu\xE9 par \idx\numexpr.
+\end{itemize}
+
+La macro \verb|\for at i| lira \emph{trois} arguments, les deux que lui passe la macro \verb-\for- et le \verb-<code>- qui doit \xEAtre ex\xE9cut\xE9 \xE0 chaque it\xE9ration puisque celui-ci n'a pas \xE9t\xE9 lu par la macro chapeau \verb-\for-. Comme la macro \verb-\for at i- est appel\xE9e \xE0 \xEAtre r\xE9cursive, il est tr\xE8s peu commode --~et maladroit~-- d'installer une r\xE9cursivit\xE9 avec trois arguments \xE0 lire \xE0 chaque appel. Pour \xE9viter cette lourdeur, la macro \verb-\for at i- ne sert que de macro chapeau pour la vraie macro r\xE9cursive \verb-\for at ii- qui n'admet aucun argument puisque, \xE9tant \emph{dans} la macro \verb-\for at i-, elle peut acc\xE9der \xE0 ses arguments.
+
+Le code de la macro \verb-\for at ii- est assez simple, le \verb|<code>| est ex\xE9cuter \xE0 la ligne \no\eee{} puis la \verb|\<macro>| est incr\xE9ment\xE9e de la valeur sign\xE9e \verb-\for at increment-. La ligne \no\fff{} n\xE9cessite un petit commentaire : le test \tidx{ifnum} s'attend \xE0 lire un nombre et d\xE9veloppe tout au maximum jusqu'\xE0 trouver un token qui ne puisse pas constituer un entier : la macro \verb|#1| va \xEAtre d\xE9velopp\xE9e et la lecture du nombre ne va pas s'arr\xEAter. Le d\xE9veloppement va continuer et la macro \verb-\cmp at sgn- va \xEAtre d\xE9velopp\xE9e \xE0 son tour. Comme son texte de remplacement est \xAB\verb|<|\xBB ou \xAB\verb|>|\xBB, la lecture du nombre va \xEAtre stopp\xE9e, mais le but recherch\xE9, c'est-\xE0-dire le d\xE9veloppement de \verb|\cmp at sgn| est effectu\xE9. Enfin, le test est construit avec \tidx{unless} ce qui signifie que ce qui se trouve jusqu'au \tidx{fi} est ex\xE9cut\xE9 si le test \emph{contraire} est v\xE9rifi\xE9. Ce test contraire correspond \xE0 une in\xE9galit\xE9 \emph{large} ($\leqslant$ ou $\geqslant$) ce qui implique qu'une it\xE9ration sera faite lorsque la \verb|\<macro>| est \xE9gale \xE0 $n_2$.
+
+\subsubsection{Imbrication de boucles : analyse du probl\xE8me}
+Comme le cas g l'a mis en \xE9vidence dans le code pr\xE9c\xE9dent, lorsque deux boucles \verb-\for- sont imbriqu\xE9es le fonctionnement attendu n'est pas obtenu et il semble qu'une seule it\xE9ration de la boucle la plus ext\xE9rieure est faite enti\xE8rement :
+
+\centrecode-\for\ii=1to4\do{\for\jj=0to2\do{(\ii,\jj)}\par}-
+
+\noindent se traduit par \xAB(1,0)(1,1)(1,2)\xBB.
+
+Il faut inventer un rem\xE8de qui permet d'imbriquer autant de boucles \verb-\for- que l'on veut. Mais tout d'abord, il faut analyser le probl\xE8me. Par chance, c'est assez simple ici. Dans un premier temps, \verb-\for at i- est appel\xE9e par \verb-\for- ce qui a pour effet de d\xE9finir la macro \verb-\for at ii- avec le texte de remplacement (auquel nous donnons le num\xE9ro~1) suivant :
+
+\centrecode-\unless\ifnum\ii\cmp at sgn4\relax
+  \for\jj=0to2\do{(\ii,\jj)}\par
+  \edef\ii{\number\numexpr\ii+\for at increment}%
+  \expandafter\for at ii
+\fi-
+
+Lorsque la macro \verb|\for at ii| est ex\xE9cut\xE9e \xE0 la ligne \no\ggg, elle est d\xE9velopp\xE9e et donc, tout ce code est plac\xE9 sur la pile pour y \xEAtre ex\xE9cut\xE9. Lorsque la 2\ieme{} ligne de la pile est ex\xE9cut\xE9e, une nouvelle boucle \xA7\for d\xE9marre:
+
+\centrecode-\for\jj=0to2\do{(\ii,\jj)}-
+
+Comme \verb|\ii| vaut 1, cette boucle va afficher \xAB(1,0)(1,1)(1,2)\xBB mais en coulisse, l'irr\xE9parable s'est d\xE9j\xE0 produit ! Ce nouvel appel \xE0 \xA7\for a red\xE9fini la macro \verb|\for at ii| avec ce texte de remplacement (appel\xE9 \no2) :
+
+\centrecode-\unless\ifnum\jj\cmp at sgn2\relax
+  (\ii,\jj)%
+  \edef\jj{\number\numexpr\jj+\for at increment}%
+  \expandafter\for at ii
+\fi-
+
+\Qu e va-t-il se passer quand la boucle interne (dont la variable est \verb|\jj|) sera termin\xE9e et que \xAB(1,0)(1,1)(1,2)\xBB sera affich\xE9? La macro \verb|\jj| vaudra 3 et \TeX{} va continuer \xE0 lire le code sur sa pile qui est le texte de remplacement \no1 amput\xE9 de ses deux premi\xE8res lignes :
+
+\centrecode-\edef\ii{\number\numexpr\ii+\for at increment}%
+  \expandafter\for at ii
+\fi-
+
+\noindent Par cons\xE9quent, \verb|\ii| va \xEAtre incr\xE9ment\xE9 (et vaudra 2). La macro \verb|\for at ii| (dont le texte de remplacement est le \no2) va \xEAtre appel\xE9e et le test
+
+\centrecode-\unless\ifnum\jj\cmp at sgn2\relax-
+
+\noindent sera faux car \verb|\jj| (qui vaut 3) a d\xE9pass\xE9 $n_2$ qui est 2. Par cons\xE9quent, aucun code ni aucune r\xE9cursivit\xE9 ne seront ex\xE9cut\xE9s. Ce test faux signe donc la fin de la boucle ext\xE9rieure.
+
+\subsubsection{Imbrication de boucles : r\xE9solution du probl\xE8me}
+Tous les probl\xE8mes viennent donc de la red\xE9finition de \verb-\for at ii- par la boucle int\xE9rieure et du fait que cette red\xE9finition survive \xE0 la fin de la boucle int\xE9rieure. Certes, ex\xE9cuter chaque boucle dans un groupe r\xE8glerait le probl\xE8me, mais cette solution de facilit\xE9 emp\xEAcherait toute globalit\xE9 au code qui est ex\xE9cut\xE9 \xE0 chaque it\xE9ration et donc diminuerait les fonctionnalit\xE9s de la boucle.
+
+Le rem\xE8de serait donc de d\xE9finir une macro \verb-\for at ii- sp\xE9cifique \xE0 chaque \xAB variable \xBB. Pour cela, la macro chapeau \verb|\for| va appeler une macro \verb|\for at i| charg\xE9e de d\xE9finir la macro r\xE9cursive \verb|\|\boxtoken{for at ii@\string\<macro>} o\xF9 \verb|\<macro>| est le d\xE9veloppement de \verb|\string#1|. Par exemple, si l'on ex\xE9cute
+
+\centrecode-\for\xx=1to5\do{X}-
+
+\noindent la macro \verb|\for| va appeler \verb|\for at i| qui va se charger de d\xE9finir et lancer la macro r\xE9cursive \verb-\-\boxtoken{for at ii@\string\xx}. Plus aucun risque de red\xE9finition n'existe, sauf si l'utilisateur fait preuve d'inconscience et utilise le m\xEAme nom de variable pour deux boucles imbriqu\xE9es.
+
+Du c\xF4t\xE9 de la m\xE9thode \xE0 utiliser, nous allons faire en sorte que \verb|\for| passe \xE0 la macro \verb|\for at i| les arguments suivants :
+
+\begin{enumerate}[label={{\ttfamily\char`\#\arabic*} :}]
+	\item la macro r\xE9cursive \verb-\-\boxtoken{for at ii@\string\<macro>};
+	\item le signe de comparaison explicitement \xE9crit "\verb|<|" ou "\verb|>|";
+	\item l'incr\xE9ment sous forme d'un entier explicitement \xE9crit;
+	\item la \verb|\<macro>| qui est l'argument \verb|#1| de \verb|\for|;
+	\item l'entier $n_2$ qui est l'argument \verb|#3| de \verb|\for|.
+\end{enumerate}
+
+Par exemple, si nous \xE9crivons
+
+\centrecode-\for\xx=1to20\do4{X}-
+
+\noindent la macro \verb|\for at i| doit \xEAtre appel\xE9e ainsi :
+
+\begin{centrage}
+	\small\verb-\for at i\-\boxtoken{for at ii@\string\xx}\verb-<{4}\xx{20}-
+\end{centrage}
+
+Le fait que les arguments \verb|#2|, \verb|#3| et \verb|#5| soient transmis explicitement sous forme de tokens de catcode 12 \xE9vite de cr\xE9er une macro pour les stocker et nous met donc \xE0 l'abri de toute red\xE9finition de cette macro par une boucle imbriqu\xE9e.
+
+Prenons le parti de stocker ces 5 arguments dans une macro \verb|\macro at args| d\xE9finie avec \verb|\edef|. Rappelons-nous que dans le texte de remplacement d'un \verb|\edef|, un \idx\noexpand est n\xE9cessaire pour bloquer le d\xE9veloppement d'une s\xE9quence de contr\xF4le : les arguments \verb|#1| et \verb|#4| sont ici concern\xE9s. Une fois la macro \verb|\macro at args| d\xE9finie, l'appel \xE0 \verb|\for at i| se fera donc par
+
+\centrecode|\expandafter\for at i\macro at args|
+
+\showcode/\catcode`\@11
+\def\for#1=#2to#3\do#4#{%
+	\edef\for at increment{\number\numexpr0#4}% lit et normalise l'argument optionnel
+	\ifnum\for at increment=\z@% s'il est nul,\xA4\idx*\z@\xA4
+		\edef\for at increment{% le red\xE9finir \xE0 -1 (si #3<#2) et 1 sinon
+			\ifnum\numexpr#3-#2\relax<\z@ -1\else 1\fi\xA4\idx*\numexpr\idx*\z@\xA4
+		}% \for at increment vaut donc 1 ou -1
+	\fi
+	\ifnum\numexpr\for at increment*(#3-#2)\relax<\z@
+		\expandafter\gobone% si argument optionnel incompatible, manger le {<code>}\xA4\xA7*\gobone[|etc]\forbidindex\gobone\xA4
+	\else
+		\edef#1{\number\numexpr#2}% initialise la \<macro>
+		\edef\macro at args{% d\xE9finit et d\xE9veloppe les arguments \xE0 passer \xE0 \for at i
+			%#1=nom de la macro r\xE9cursive :
+			\expandafter\noexpand\csname for at ii@\string#1\endcsname\xA4\idx*\csname\idx*\endcsname\idx*\string\xA4
+			\ifnum\for at increment<\z@ <\else >\fi% #2=signe de comparaison\xA4\idx*\z@\xA4
+			{\for at increment}% #3=incr\xE9ment
+			\noexpand#1% #4=\<macro>\xA4\idx*\noexpand\xA4
+			{\number\numexpr#3\relax}% #5=entier n2\xA4\idx*\number\idx*\numexpr\xA4
+		}%
+		\antefi% externalise la ligne ci-dessous de la port\xE9e du test\xA4\xA7*\antefi\xA4
+		\expandafter\for at i\macro at args% appelle \for at i avec les arguments d\xE9finis ci-dessus
+	\fi
+}
+
+% #1=nom de la macro r\xE9cursive de type "\for at ii@\<macro>"
+% #2=signe de comparaison  % #3=incr\xE9ment
+% #4=\<macro>  % #5=entier n2  % #6=<code> \xE0 ex\xE9cuter
+\long\def\for at i#1#2#3#4#5#6{%\xA4\idx*\long\xA4
+	\def#1{% d\xE9finit la sous macro r\xE9cursive
+		\unless\ifnum#4#2#5\relax% tant que la \<macro> variable n'a pas d\xE9pass\xE9 n2\xA4\tidx*{unless}\xA4
+			\afterfi{% rendre la r\xE9cursivit\xE9 terminale\xA4\xA7*\afterfi\idx*{r\xE9cursivit\xE9!terminale}\xA4
+				#6% ex\xE9cute le code\xA4\defline\bbb\xA4
+				\edef#4{\number\numexpr#4+#3\relax}% incr\xE9mente la \<macro>
+				#1% recommence
+			}%
+		\fi
+	}%
+	#1% appelle la sous-macro r\xE9cursive\xA4\defline\ccc\xA4
+}%
+\catcode`\@=12
+\for\ii=1to4\do{\for\jj=0to2\do{(\ii,\jj)}\par}\medbreak\xA4\idx*\medbreak\xA4
+
+\for\carA= `\A to `\E \do{\for\carB= `w to `z \do{\char\carA\char\carB}\quad}\xA4\idx*[|etc]\quad\forbidindex\quad\xA4/
+
+\begin{exercice}
+En l'\xE9tat, la boucle est parcourue autant de fois que l'imposent les bornes et l'incr\xE9ment. Or, dans certains cas, une condition programm\xE9e par l'utilisateur devient vraie au cours des it\xE9rations et \xE0 partir de ce moment, ex\xE9cuter les it\xE9rations suivantes devient ind\xE9sirable. Comment programmer une macro \xA7\exitfor qui, ins\xE9r\xE9e dans le \verb|<code>| \xE0 ex\xE9cuter, permette de sortir pr\xE9matur\xE9ment de la boucle ?
+\solution
+La macro \xA7\exitfor est susceptible de se trouver dans le \verb|<code>| \xE0 la ligne \no\bbb. Cette macro doit donc annuler l'appel r\xE9cursif de la ligne \no\ccc. Il y a plusieurs moyens de le faire, le plus simple est de charger \xA7\exitfor de red\xE9finir la macro r\xE9cursive \verb|#1| comme ayant un texte de remplacement vide :
+
+\showcode/\catcode`\@11
+\long\def\for at i#1#2#3#4#5#6{%\xA4\idx*\long\xA4
+	\def\exitfor{\def#1{}}%\xA4\xA7*\exitfor\xA4
+	\def#1{% d\xE9finit la sous macro r\xE9cursive
+		\unless\ifnum#4#2#5\relax% tant que la variable n'a pas d\xE9pass\xE9 l'entier max\xA4\tidx*{unless}\xA4
+			\afterfi{% rendre la r\xE9cursivit\xE9 terminale\xA4\xA7*\afterfi\idx*{r\xE9cursivit\xE9!terminale}\xA4
+				#6% ex\xE9cute le code\xA4\defline\bbb\xA4
+				\edef#4{\number\numexpr#4+#3\relax}% incr\xE9mente la variable #1\xA4\idx*\number\idx*\numexpr\xA4
+				#1% recommence
+			}%
+		\fi
+	}%
+	#1% appelle la sous-macro r\xE9cursive
+}%
+\catcode`\@=12
+\for\ii= 1 to 9 \do{\string\ii{} vaut \ii.\ifnum\ii=5 \exitfor\fi\par}\xA4\idx*\string\xA7*\exitfor\xA4/
+
+Cela fonctionne correctement car il n'y a aucune boucle \verb|for| imbriqu\xE9e.
+
+Dans le cas de boucles imbriqu\xE9es, la macro \xA7\exitfor va \xEAtre d\xE9finie plusieurs fois (une fois par imbrication). Par cons\xE9quent, la derni\xE8re d\xE9finition, celle de la boucle la plus int\xE9rieure, \xE9crase les autres. On peut donc sortir de la boucle la plus int\xE9rieure, mais plus des boucles de niveau sup\xE9rieur.
+
+Le rem\xE8de le plus simple est de donner comme argument \xE0 \xA7\exitfor la \verb|\<macro>| correspondant \xE0 la boucle de laquelle on souhaite sortir. Ainsi, \xA7\exitfor\verb|#1| red\xE9finirait la macro \verb-\-\boxtoken{for at ii@\string#1} comme ayant un texte de remplacement vide. Pour \xEAtre complets sur le sujet, nous cr\xE9erons aussi la macro \xA7\ifexitfor de syntaxe
+
+\centrecode-\ifexitfor\<macro>{<code vrai>}{<code faux>}-
+
+\noindent Ainsi, \xA7\ifexitfor\verb|\<macro>| permet de savoir, en dehors de la boucle de variable \verb|\<macro>|, si on en est pr\xE9matur\xE9ment sorti ou pas. D\xE9finir \xA7\ifexitfor fait appel au test \verb|\ifx| et \xE0 la macro \idx\empty et devient donc, en anticipant un peu, une bonne transition vers le chapitre suivant qui aborde d'autres tests que propose \TeX.
+
+Le code ci-dessous permet de voir plusieurs fa\xE7ons, plus ou moins rapides, de sortir de 2 boucles imbriqu\xE9es :
+
+\showcode/\def\exitfor#1{% #1=\<macro> correspondant \xE0 la boucle de laquelle on veut sortir\xA4\xA7*\exitfor\xA4
+	\defname{for at ii@\string#1}{}\xA4\idx*\csname\idx*\endcsname\idx*\string\xA7*\defname\xA4
+}
+
+\def\ifexitfor#1{% envoie vrai si on est pr\xE9matur\xE9ment sorti de la boucle de \<macro> #1\xA4\xA7*\ifexitfor\xA4
+	% si la macro r\xE9cursive est \xE9gale \xE0 la macro "\empty"
+	\expandafter\ifx\csname for at ii@\string#1\endcsname\empty\xA4\idx*\string\idx*\empty\xA4
+		\expandafter\firstoftwo% c'est qu'on est sortir pr\xE9matur\xE9ment, renvoyer "vrai"\xA4\xA7*\firstoftwo\xA4
+	\else
+		\expandafter\secondoftwo% sinon, renvoyer "faux"\xA4\xA7*\secondoftwo\xA4
+	\fi
+}
+
+% on ne sort QUE de la boucle int\xE9rieure quand \ii=3 donc
+% les boucles sont normalement ex\xE9cut\xE9es pour \ii=4 et \ii=5
+a. \for\ii=1 to 5\do1{%
+     \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\jj\fi}%\xA4\xA7*\exitfor\xA4
+     \qquad
+   }
+
+% on sort de la boucle ext\xE9rieure lorsque \ii=3 donc la boucle
+% int\xE9rieure est faite enti\xE8rement m\xEAme lorsque \ii=3
+b. \for\ii=1 to 5\do1{%
+     \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\ii\fi}%\xA4\xA7*\exitfor\xA4
+     \qquad
+   }
+
+% on sort de la boucle int\xE9rieure lorsque \ii=3
+% et aussi de la boucle ext\xE9rieure \xE0 l'aide de \ifexitfor
+c. \for\ii=1 to 5\do1{%
+     \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\jj\fi}%\xA4\xA7*\exitfor\xA4
+     \ifexitfor\jj{\exitfor\ii}{}% si on est sorti de \jj, sortir aussi de \ii\xA4\xA7*\exitfor\xA7*\ifexitfor\xA4
+     \qquad
+   }/
+\end{exercice}\xA7*\for[|)]{}
+
+\chapter[\Qu elques autres tests]{Quelques autres tests}
+Apr\xE8s avoir touch\xE9 du doigt la syntaxe g\xE9n\xE9rale des tests et leurs particularit\xE9s concernant la fa\xE7on dont ils se d\xE9veloppent, apr\xE8s avoir examin\xE9 plus particuli\xE8rement le test \tidx{ifnum}, nous allons dans ce chapitre d\xE9couvrir quelques autres tests de \TeX{}. Le but n'est pas de les passer tous en revue, mais d'examiner ceux qui sont le plus utiles et les utiliser pour en cr\xE9er d'autres.
+
+\section{Le test \texttt{\textbackslash{}ifx}}\tidx*[|(]{ifx}
+\subsection{\Qu e teste \texttt{\char`\\ifx} ?}
+Un des tests les plus utilis\xE9s est sans doute le test \tidx{ifx}.
+
+\begin{regle}
+Le test \tidx{ifx} compare les significations des deux \emph{tokens} qui le suivent. Il a la syntaxe suivante :
+
+\centrecode-\ifx<token1><token2>
+	<code vrai>
+\else
+	<code faux>
+\fi-
+
+Il est vrai si la signification des deux tokens est la m\xEAme. Parmi toutes les possibilit\xE9s qui se pr\xE9sentent selon la nature des deux tokens, les trois cas suivants sont les plus courants :
+
+\begin{enumerate}
+	\item si les deux tokens sont des caract\xE8res, alors le test est positif si les caract\xE8res sont identiques, c'est-\xE0-dire si leur \idx{code de caract\xE8re} \emph{et} leur catcode sont \xE9gaux;
+	\item si les deux tokens sont des \idx{primitive}s, le test est positif si les primitives sont les m\xEAmes;
+	\item si les deux tokens sont des macros ou des caract\xE8res actifs\idx*{caract\xE8re actif}, le test \verb-\ifx- compare leurs textes de remplacement : le test est positif si les textes de remplacement sont identiques, c'est-\xE0-dire constitu\xE9s des m\xEAmes tokens avec les m\xEAmes catcodes. La comparaison tient \xE9galement compte des propri\xE9t\xE9s de ces macros, notamment si elles sont \idx\long ou \idx\outer.
+	
+	Deux macros non d\xE9finies sont \xE9gales pour \verb-\ifx-, quels que soient leurs noms.
+\end{enumerate}
+\end{regle}
+
+Contrairement \xE0 \tidx{ifnum}, le test \tidx{ifx} ne d\xE9clenche pas un d\xE9veloppement maximal et donc, les deux tokens sont compar\xE9s tels quels.
+
+Si deux tokens appartiennent \xE0 deux cat\xE9gories diff\xE9rentes parmi les trois list\xE9es dans la r\xE8gle ci-dessus, le test sera faux. Par exemple, si une macro \verb-\foo- a le texte de remplacement \xAB\verb|a|\xBB, alors le test \verb-\ifx a\foo- est faux :
+
+\showcode/\def\foo{a}\ifx a\foo vrai\else faux\fi/
+
+En effet, le premier token \xAB\verb|a|\xBB est un caract\xE8re, une sorte de primitive pour \TeX{} alors que le second \verb-\foo- est une macro. Notons que la primitive \idx\meaning donne une bonne id\xE9e de ce qu'est la \emph{signification} d'un token, m\xEAme si elle ne dit rien sur les catcodes des tokens composant le texte de remplacement d'une macro (voir les cas \nos6 et 7 ci-dessous) :
+
+\showcode/1) \meaning9\par% un caract\xE8re de catcode 12\xA4\idx*\meaning\idx*{catcode!12\space(autre)}\xA4
+2) \meaning a\par% une lettre
+3) \def\foo{a}\meaning\foo\par% une macro
+4) \long\def\foo{a}\meaning\foo\par% une macro d\xE9clar\xE9e \long\xA4\idx*\long\xA4
+5) \meaning\sdlkfj\par% une macro ind\xE9finie
+6) \edef\foo{\string a}\meaning\foo\par%\foo contient un "a" de catcode 12\xA4\idx*\string\xA4
+7) \def\foo{a}\meaning\foo\par%\foo contient un "a" de catcode 11/
+
+Pour fixer les id\xE9es, effectuons quelques autres tests qui montrent comment r\xE9agit \verb|\ifx| :
+
+\showcode/a) \ifx abvrai\else faux\fi\quad% a est n'est pas \xE9gal \xE0 b
+b) \ifx++vrai\else faux\fi\quad% le caract\xE8re "+" est \xE9gal \xE0 "+"
+c) \ifx\relax\par vrai\else faux\fi\quad% \relax n'est pas la m\xEAme primitive que \par
+d) \ifx\par\par vrai\else faux\fi\quad% \par et \par sont les m\xEAmes primitives
+e) \ifx\sdfk\qlms vrai\else faux\fi\quad% 2 macros non d\xE9finies sont \xE9gales
+f) \def\foo{abcd}\def\bar{abc}% \foo et \bar ont des textes de remplacement diff\xE9rents
+   \ifx\foo\bar vrai\else faux\fi\quad
+g) \def\foo{abcd}\def\bar{abcd }% \foo et \bar ont des textes de remplacement diff\xE9rents
+   \ifx\foo\bar vrai\else faux\fi\quad
+h) \def\foo{abcd}\def\bar{abcd}
+   \ifx\foo\bar vrai\else faux\fi\quad% \foo et \bar ont les m\xEAmes textes de remplacement
+i) \long\def\foo{a}\def\bar{a}\xA4\idx*[|etc]\long\forbidindex\long\xA4
+   \ifx\foo\bar vrai\else faux\fi\quad% \foo est \long, \bar ne l'est pas
+j) \edef\foo{\string a}% \foo contient un "a" de catcode 12\xA4\idx*{catcode!11\space(lettre)}\idx*{catcode!12\space(autre)}\idx*\string\xA4
+   \def\bar{a}% \bar contient un "a" de catcode 11
+   \ifx\foo\bar vrai\else faux\fi/
+
+\begin{exercice}
+Il a \xE9t\xE9 dit que le test \verb-\ifx- \xE9tait sensible aux codes de cat\xE9gorie. \xC9crire une macro\xA7*\cmpmacro
+
+\centrecode-\cmpmacro<\macroA><\macroB>{<code vrai>}{<code faux>}-
+
+\noindent qui comparera les macros contenues dans ses deux premiers arguments sans tenir compte des codes de cat\xE9gorie des tokens qui composent leurs textes de remplacement.
+\solution
+L'id\xE9e et de d\xE9tok\xE9niser le texte de remplacement des deux macros, d'assigner ces deux textes d\xE9tok\xE9nis\xE9s \xE0 des macros auxiliaires et enfin, de comparer ces deux macros avec \verb-\ifx-. Pour ne pas laisser ces deux macros auxiliaires derri\xE8re nous, cr\xE9ons-les dans un groupe semi-simple que nous refermerons apr\xE8s la comparaison. Remarquons \xE0 cette occasion que la paire \idx\begingroup et \idx\endgroup peut \xEAtre \xAB imbriqu\xE9e \xBB avec les \verb-\ifx-, \tidx{else} et \tidx{fi} d'un test.
+
+\showcode/\def\cmpmacro#1#2{%\xA4\xA7*\cmpmacro\xA4
+	\begingroup\xA4\idx*\begingroup\xA4
+	\edef\tempa{\detokenize\expandafter{#1}}\edef\tempb{\detokenize\expandafter{#2}}%\xA4\idx*\detokenize\xA4
+	\ifx\tempa\tempb% si \xE9galit\xE9
+		\endgroup\expandafter\firstoftwo% ferme le groupe et lit 1er argument\xA4\idx*\endgroup\xA7*\firstoftwo\xA4
+	\else
+		\endgroup\expandafter\secondoftwo% sinon, ferme le groupe et lit le 2e argument\xA4\xA7*\secondoftwo\xA4
+	\fi
+}
+a) \edef\foo{\string a}\def\bar{a}\xA4\idx*\string\xA4
+   \cmpmacro\foo\bar{vrai}{faux}\qquad
+b) \edef\foo{\detokenize{$i^2=-1$\relax}}\def\bar{$i^2=-1$\relax}
+   \cmpmacro\foo\bar{vrai}{faux}\xA4\xA7*\cmpmacro\xA4/
+\end{exercice}
+
+\subsection{Le test \texttt{\char`\\ifx}, la \texttt{\char`\\let}-\xE9galit\xE9 et les quarks}
+Voici une r\xE8gle particuli\xE8re qu'il est utile de connaitre :
+
+\begin{regle}
+Le test \tidx{ifx} ne distingue pas deux tokens \idx\let-\xE9gaux.
+\end{regle}
+
+Autrement dit, si un token de type \verb|\<macro>| est rendu \xE9gal au token $x$ avec \idx\let, alors, \verb-\ifx- verra \verb|\<macro>| et $x$ \xE9gaux.
+
+Nous pouvons l'observer ci-dessous o\xF9 des tokens, \xE0 chaque fois \idx\let-\xE9gaux, rendent tous les tests vrais :
+
+\showcode/a) \let\rien\relax      \ifx\rien\relax vrai\else faux\fi\qquad
+b) \let\AA=a            \ifx a\AA vrai\else faux\fi\qquad
+c) \let\foo=_\let\bar=_ \ifx\foo\bar vrai\else faux\fi/
+
+Pour exploiter la r\xE8gle pr\xE9c\xE9dente, il est parfois commode de cr\xE9er des macros sp\xE9ciales dont le d\xE9veloppement est elles-m\xEAmes, autrement dit \emph{invariantes} par d\xE9veloppement ! Elles portent le nom de \xAB\idx[|(]{quark}s\xBB. Voici comment nous pourrions d\xE9finir un quark nomm\xE9 \xA7\quark :
+
+\centrecode-\def\quark{\quark}-
+
+\noindent Bien \xE9videmment, il ne faut jamais qu'un quark ne soit ex\xE9cut\xE9 puisqu'en se d\xE9veloppant, il ne change pas : cette propri\xE9t\xE9 m\xE8nerait \xE0 une \idx{boucle infinie} dont on ne peut sortir que par interruption manuelle. \xC0 vrai dire, les quarks ne sont utiles que pour les comparaisons via \tidx{ifx}. Essayons de comprendre pourquoi en prenant par exemple une macro \verb-\test- d\xE9finie comme suit :
+
+\centrecode-\def\test{\quark}-
+
+\noindent Dans ce cas, le test \xAB\verb|\ifx\test\quark|\xBB est vrai parce que \xA7\quark est un quark. Il serait faux s'il ne l'\xE9tait pas. En effet, \tidx{ifx} compare le texte de replacement de \verb|\test| et celui de \xA7\quark : ce texte de remplacement est bien \xA7\quark dans les deux cas.
+
+Le test est \xE9galement positif si \verb|\test| est d\xE9fini par
+
+\centrecode-\let\test=\quark-
+
+\noindent puisque dans ce cas, deux macros \idx\let-\xE9gales sont compar\xE9es.
+
+\showcode/\def\quark{\quark}% d\xE9finit un quark\xA4\xA7*\quark\xA4
+1) \def\test{\quark} \ifx\quark\test vrai\else faux\fi
+\qquad
+2) \let\test=\quark  \ifx\quark\test vrai\else faux\fi\xA4\xA7*\quark\xA4/
+
+Le fait que \tidx{ifx} donne un test vrai aussi bien pour une macro d\xE9finie par \idx\def ou par \idx\let se r\xE9v\xE8le bien pratique et constitue une particularit\xE9 des quarks.
+
+\begin{regle}[D\xE9finition et propri\xE9t\xE9s]
+Un quark est une macro dont le texte de remplacement est constitu\xE9 de la macro elle-m\xEAme.
+
+Un quark ne doit \emph{jamais} \xEAtre ex\xE9cut\xE9, car \xE9tant invariant par d\xE9veloppement, son traitement par \TeX{} engendrerait une \idx{boucle infinie}.\medbreak
+
+Si \verb|\<quark>| est un quark et si \verb|\<macro>| est d\xE9finie par
+
+\begin{centrage}
+\small\verb|\def\<macro>{\<quark>}|\quad {\normalsize ou par}\quad\verb|\let\<macro> = \<quark>|
+\end{centrage}
+
+\noindent alors, le test \verb|\ifx\<macro>\<quark>| sera vrai dans les deux cas.
+\end{regle}\idx*[|)]{quark}
+
+\section{Applications du test \texttt{\textbackslash ifx}}
+\subsection{Tester si un argument est vide}\idx*[|(]{argument!vide}
+Il arrive souvent qu'il faille tester si un argument est vide (c'est-\xE0-dire constitu\xE9 de 0 token). La m\xE9thode na\xEFve, mais aussi la plus efficace est la suivante : on assigne avec \verb|\def| cet argument \xE0 une \verb|\<macro>| temporaire. Ensuite, on compare avec \verb-\ifx- cette \verb|\<macro>| et la macro nomm\xE9e \idx\empty, d\xE9finie dans plain-\TeX{}\footnote{La macro \xE9quivalente \texttt{\string\@empty} est d\xE9finie dans le format \LaTeX.}, dont le texte de remplacement est vide:\xA7*\ifempty[|(]
+
+\centrecode-\def\empty{}-
+
+Cela donne le code suivant :
+
+\showcode/\def\ifempty#1{%\xA4\xA7*\ifempty\xA4
+	\def\tempa{#1}% stocke l'argument #1 dans \tempa\xA4\defline\aaa\xA4
+	\ifx\tempa\empty% si \tempa = \empty
+		\expandafter\firstoftwo% 1er argument\xA4\xA7*\firstoftwo\xA4
+	\else
+		\expandafter\secondoftwo% sinon, second\xA4\xA7*\secondoftwo\xA4
+	\fi
+}
+a) \ifempty{abc}{vide}{pas vide}\qquad
+b) \ifempty{}{vide}{pas vide}\qquad
+c) \ifempty{ }{vide}{pas vide}\qquad
+d) \ifempty{\empty}{vide}{pas vide}\xA4\defline\bbb\xA4/
+
+\begin{exercice}\label{argument.vide}
+Expliquer pourquoi le test est n\xE9gatif \xE0 la ligne \no\bbb{} du code ci-dessous
+\solution
+La ligne \no\aaa{} effectue l'action suivante :
+
+\centrecode-\def\tempa{\empty}-
+
+Le test \verb|\ifx\tempa\empty| compare donc les deux textes de remplacement de ces macros qui sont \idx\empty pour la premi\xE8re et un texte vide pour la seconde. Ces deux textes de remplacement ne sont pas \xE9gaux ce qui explique que le test est n\xE9gatif.
+\end{exercice}
+
+La macro \xA7\ifempty fonctionne parfaitement, mais elle n'est \emph{pas} purement d\xE9veloppable \xE0 cause de la pr\xE9sence du \idx\def dans son texte de remplacement. Pour rendre la macro d\xE9veloppable, l'astuce consiste \xE0 utiliser le fait que lorsqu'un argument \verb|#1| d'une macro est vide, tout se passe comme s'il n'existait pas dans son texte de remplacement.  Dans ce cas, les tokens qui sont juste avant et juste apr\xE8s \verb|#1| deviennent cons\xE9cutifs. Il suffit que ces deux tokens soient les m\xEAmes (par exemple \xAB\verb|_|\xBB) pour que le test \xAB\verb|\ifx_#1_|\xBB devienne positif lorsque \verb|#1| est vide :
+
+\showcode/\def\empty{}
+\long\def\ifempty#1{%\xA4\xA7*\firstoftwo\xA7*\secondoftwo\xA7*\ifempty\xA4
+  \ifx_#1_\expandafter\firstoftwo
+  \else\expandafter\secondoftwo
+  \fi}
+a) \ifempty{abc}{vide}{pas vide}\qquad
+b) \ifempty{}{vide}{pas vide}\qquad
+c) \ifempty{ }{vide}{pas vide}\qquad
+d) \ifempty{\empty}{vide}{pas vide}\qquad
+e) \edef\foo{\ifempty{abc}{vide}{pas vide}}\meaning\foo/
+
+Bien \xE9videmment, au lieu de \xAB\verb-_-\xBB, nous aurions aussi pu utiliser \xAB\verb-|-\xBB, \idx\empty ou tout autre token. La macro fonctionne bien, mais il va se trouver des cas particuliers o\xF9 elle va donner des faux positifs ! En effet, le test \verb-\ifx<token>#1<token>- est vrai si \verb|#1| est vide, mais il sera \emph{aussi} vrai si \verb-#1- commence par le \verb|<token>|. Nous pouvons l'observer ici o\xF9 \xAB\verb|W|\xBB est pris comme token de comparaison qui, contrairement \xE0 \xAB\verb|_|\xBB peut \xEAtre \emph{affich\xE9} par \TeX{}. Le cas \no4 met en \xE9vidence le probl\xE8me :
+
+\showcode/\long\def\ifempty#1{%\xA4\xA7*\firstoftwo\xA7*\secondoftwo\xA7*\ifempty\xA4
+  \ifx W#1W\expandafter\firstoftwo
+  \else    \expandafter\secondoftwo
+  \fi}
+1) \ifempty{foobar}{vide}{pas vide}\qquad
+2) \ifempty{}{vide}{pas vide}\qquad
+2) \ifempty{\empty}{vide}{pas vide}\qquad
+4) \ifempty{Wagons}{vide}{pas vide}/
+
+On peut observer que le test \verb|\ifx| a compar\xE9 le \xAB\verb|W|\xBB qui le suit et le \xAB\verb|W|\xBB de \xAB \verb|Wagons|\xBB. Comme il est vrai, tout ce qui est jusqu'au \verb|\else| a \xE9t\xE9 affich\xE9.
+
+Pour se pr\xE9munir de cet inconv\xE9nient, la m\xE9thode la plus commun\xE9ment utilis\xE9e consiste \xE0 \emph{d\xE9tok\xE9niser} l'argument \verb|#1| et l'entourer de deux tokens qui ne sont pas de catcode 12 (\idx\relax est habituellement utilis\xE9 dans ce cas). Pour que cela fonctionne, \xAB\verb|\detokenize{#1}|\xBB doit \xEAtre d\xE9velopp\xE9 avant que le test n'entre en jeu et n\xE9cessite donc un pont d'\idx\expandafter :
+
+\centrecode-\expandafter\ifx\expandafter\relax\detokenize{#1}\relax-
+
+Avec cette m\xE9thode, le test n'est positif \emph{que} lorsque \verb|#1| est vide. En effet,
+
+\begin{enumerate}
+	\item si \verb|#1| commence par un espace, \verb|\detokenize{#1}| se d\xE9veloppe en un espace (de catcode 10) suivi d'autres tokens. Le test se fera donc entre \idx\relax et \verb*| | et sera faux;
+	\item si \verb|#1| commence par un autre token, le d\xE9veloppement de \idx\detokenize\verb|{#1}| commence par un caract\xE8re de catcode 12. La comparaison entre \idx\relax et ce token est fausse ;
+	\item enfin, si \verb|#1| est vide, \verb|\detokenize{}| se d\xE9veloppe en 0 token et donc, les primitives \idx\relax deviennent cons\xE9cutives et sont vues \xE9gales par le test \tidx{ifx} qui est alors positif.
+\end{enumerate}
+
+\showcode/\long\def\ifempty#1{%\xA4\xA7*\firstoftwo\xA7*\secondoftwo\xA7*\ifempty\xA4
+	\expandafter\ifx\expandafter\relax\detokenize{#1}\relax\xA4\idx*\detokenize\xA4
+		\expandafter\firstoftwo
+	\else
+		\expandafter\secondoftwo
+	\fi
+}
+a) \ifempty{abc}{vide}{pas vide}\qquad
+b) \ifempty{}{vide}{pas vide}\qquad
+c) \ifempty{ }{vide}{pas vide}\qquad
+d) \ifempty{\relax}{vide}{pas vide}\qquad
+e) \edef\foo{\ifempty{abc}{vide}{pas vide}}\meaning\foo/\xA7*\ifempty[|)]%
+
+Utiliser \idx\detokenize est la seule m\xE9thode d\xE9veloppable qui soit vraiment infaillible, mais elle a le d\xE9savantage d'\xEAtre un peu lourde \xE0 \xE9crire, c'est pourquoi on lui pr\xE9f\xE8re souvent
+
+\centrecode-\ifx\empty#1\empty-
+
+\noindent tout en restant conscient des faux positifs qu'elle peut engendrer dans les cas --~le plus souvent improbables~-- o\xF9 \verb-#1- commence par la macro \idx\empty ou toute autre macro \idx\let-\xE9gale \xE0 \idx\empty.
+\grandsaut
+
+\begin {exercice}
+\label{reverse}Programmer une macro \xA7\reverse, admettant comme argument un \verb|<mot>| et dont le d\xE9veloppement maximal est le \verb|<mot>| \xE9crit dans l'ordre inverse.
+
+Par exemple, \xA7\reverse\verb|{foobar}| donne \xAB\verb|raboof|\xBB.
+\solution
+Pour y parvenir, il faut imaginer deux r\xE9servoirs, A et B recevant des caract\xE8res. L'algorithme est le suivant :
+\begin{algo}
+	\item mettre le \verb|<mot>| dans le r\xE9servoir A et initialiser le r\xE9servoir B \xE0 \verb|<vide>| ;
+	\item prendre le premier caract\xE8re du r\xE9servoir A et le mettre en \emph{premi\xE8re} position dans le r\xE9servoir B ;
+	\item si le r\xE9servoir A n'est pas vide, retourner au point 2.
+\end{algo}
+
+Avec des arguments d\xE9limit\xE9s, il est tr\xE8s facile de construire de tels r\xE9servoirs tout en gardant la macro purement d\xE9veloppable. D\xE9cidons pour l'instant que ces d\xE9limiteurs sont des points. La structure des arguments sera donc :
+
+\centrecode-<r\xE9servoir A>.<r\xE9servoir B>.-
+
+\noindent Voici ce que sont les \xE9tapes pour inverser le texte \xAB abcd \xBB :
+\begin{center}
+	\verb|abcd..|${}\longrightarrow{}$\verb|bcd.a.|${}\longrightarrow{}$\verb|cd.ba.|${}\longrightarrow{}$\verb|d.cba.|${}\longrightarrow{}$\verb|.dcba.|
+\end{center}
+
+Le choix du point interdit que le \verb|<mot>| en contienne, ce qui n'est pas absurde en soi. Cependant, pour plus de s\xE9curit\xE9, nous prendrons \verb|\@nil| comme d\xE9limiteur. Le code de la macro \xA7\reverse ne pr\xE9sente aucune difficult\xE9 particuli\xE8re :
+
+\showcode/\catcode`\@11
+\def\reverse#1{%\xA4\xA7*\reverse\xA4
+	\ifempty{#1}
+		{}% s'il n'y a rien \xE0 inverse, ne rien faire
+		{\reverse at i#1\@nil\@nil}% initialisation des r\xE9servoirs et appeler \reverse at i
+}
+\def\reverse at i#1#2\@nil#3\@nil{% #1 est le 1er caract\xE8re du r\xE9servoir A
+	\ifempty{#2}% si ce qui reste apr\xE8s ce 1er caract\xE8re est vide\xA4\xA7*\ifempty\xA4
+		{#1#3}% renvoyer #1#3 qui est le r\xE9sultat final
+		{\reverse at i#2\@nil#1#3\@nil}% sinon, recommencer en d\xE9pla\xE7ant #1
+		                            % en 1re position du r\xE9servoir B
+}
+\catcode`\@12
+a) \reverse{foobar}\qquad
+b) \edef\foo{\reverse{Bonjour}}\meaning\foo\qquad
+c) \reverse{Bonjour le monde}\qquad
+d) \reverse{Bonjour{ }le{ }monde}\xA4\xA7*\reverse\xA4/
+
+Selon la r\xE8gle de la page~\pageref{argument.espace}, les espaces qui ne sont pas entre accolades sont ignor\xE9s lorsque lus comme argument par une macro. Il est donc normal que \xAB Bonjour le monde \xBB donne un r\xE9sultat invers\xE9 sans espace.
+\end {exercice}
+
+Le simple fait pour pouvoir tester de fa\xE7on fiable si un argument est vide ouvre d\xE9j\xE0 la voie \xE0 d'autres tests\ldots{}\idx*[|)]{argument!vide}
+
+\subsection{Tester si un code contient un motif}\label{test.code.contient.motif}
+Le but est d'\xE9laborer un test qui v\xE9rifie si un \verb-<code>- contient un autre code que l'on appelle \verb-<motif>-. Nous allons tenter d'\xE9crire une macro \xA7\ifin[|(] dont voici la syntaxe :\label{ifin}
+
+\centrecode-\ifin{<code>}{<motif>}{<vrai>}{<faux>}-
+
+\noindent Le code \verb-<vrai>- sera ex\xE9cut\xE9 si \verb-<code>- contient \verb-<motif>- et le code \verb|<faux>| le sera dans le cas contraire.
+
+Comme nous l'avions fait avec les macros \xA7\rightof et \xA7\leftof du chapitre \ref{rightof} et \ref{leftof} de la partie 2, nous allons utiliser une macro auxiliaire \xE0 arguments d\xE9limit\xE9s. Cette macro \verb-\ifin at i- sera situ\xE9e \xE0 l'int\xE9rieur du texte de remplacement de \xA7\ifin de telle sorte qu'elle puisse acc\xE9der aux arguments de \xA7\ifin. Elle aura le \idx{texte de param\xE8tre} suivant :
+
+\centrecode-\def\ifin at i##1#2##2\@nil{code \xE0 d\xE9finir}-
+
+\noindent Ainsi, les arguments d\xE9limit\xE9s \verb|##1| et \verb|##2| collectent ce qui se trouve respectivement avant et apr\xE8s le \verb|<motif>| qui est l'argument \verb|#2| de la macro chapeau.
+
+L'id\xE9e est que la macro \xA7\ifin appelle la macro \verb-\ifin at i- de cette fa\xE7on :
+
+\centrecode-\ifin at i#1#2\@nil-
+
+\noindent o\xF9 le \verb|<motif>| (argument \verb-#2-) est ajout\xE9 apr\xE8s le \verb|<code>| (argument \verb|#1|) afin de satisfaire la macro \xE0 argument d\xE9limit\xE9 \verb|\ifin at i| m\xEAme dans le cas o\xF9 \verb|#1| ne contient pas \verb|#2|. Avec cet appel, de deux choses l'une :
+
+\begin{itemize}
+	\item soit \verb-#1- contient d\xE9j\xE0 \verb-#2- et donc la premi\xE8re occurrence de \verb-#2- est dans \verb-#1- et nous pouvons donc affirmer que ce qui se trouve apr\xE8s cette premi\xE8re occurrence (qui est l'argument \verb|##2| de \verb|\ifin at i|) n'est pas vide puisqu'au moins constitu\xE9 de \verb-#2- que nous avons rajout\xE9;
+	\item soit \verb-#1- ne contient pas \verb-#2-, ce qui fait que la premi\xE8re occurrence de \verb-#2- est le \verb-#2- que nous avons ajout\xE9 juste devant le \verb|\@nil|. Par cons\xE9quent, ce qui se trouve apr\xE8s cette occurrence est vide.
+\end{itemize}
+
+Il suffit donc de tester si ce qui est apr\xE8s la premi\xE8re occurrence de \verb-#2- est vide ou pas, ce que fait la ligne \no4 du code ci-dessous :
+
+\showcode/\catcode`\@11
+\def\ifin#1#2{%\xA4\xA7*\ifin\xA4
+	\def\ifin at i##1#2##2\@nil{% d\xE9finit la macro auxiliaire
+		\ifempty{##2}% si ce qu'il y a derri\xE8re le motif est vide\xA4\xA7*\ifempty\xA4
+			\secondoftwo% aller \xE0 "faux"\xA4\xA7*\secondoftwo\xA4
+			\firstoftwo% sinon \xE0 "vrai"\xA4\xA7*\firstoftwo\xA4
+	}%
+	\ifin at i#1#2\@nil% appel de la macro auxiliaire
+}
+\catcode`\@12
+a) \ifin{abc\relax1}{bc}{vrai}{faux}\qquad
+b) \ifin{abc \relax1}{c\relax}{vrai}{faux}\qquad
+c) \ifin{abc \relax1}{ }{vrai}{faux}\qquad
+d) \ifin{abc \relax1}{}{vrai}{faux}\qquad
+e) \ifin{}{a}{vrai}{faux}/
+
+Le gros inconv\xE9nient des arguments d\xE9limit\xE9s est le d\xE9faut que nous avions signal\xE9 avec la macro \xA7\rightof \xE0 la page~\pageref{rightof.et.accolades}. Le \verb|<motif>| ne peut pas contenir d'accolades ouvrantes puisqu'elles se retrouveraient dans le texte de param\xE8tre de \verb|\ifin at i| et en fausseraient la d\xE9finition. Nous allons donc nous limiter \xE0 un code et un motif sans accolades\ldots{} Avant de trouver mieux !\xA7*\ifin[|)]
+
+\begin{exercice}\label{ifstart}
+\xC9crire une macro \xA7\ifstart[|(] de syntaxe
+
+\centrecode-\ifstart{<code>}{<motif>}{<vrai>}{<faux>}-
+
+\noindent qui teste si le \verb|<code>| commence par le \verb|<motif>| et ex\xE9cute \verb|<vrai>| si c'est le cas et \verb|<faux>| sinon.
+\solution
+La m\xE9thode est tr\xE8s similaire \xE0 celle d\xE9ploy\xE9e dans \xA7\ifin. Dans l'homologue de \verb-\ifin at i- qui est \verb|\ifstart at i|, il suffira de tester si ce qui est \emph{avant} la premi\xE8re occurrence du motif (c'est-\xE0-dire \verb-##1-) est vide ou pas. Ce qui donne ce code :
+
+\showcode/\catcode`\@11
+\def\ifstart#1#2{%
+	\def\ifstart at i##1#2##2\@nil{\ifempty{##1}}%\xA4\xA7*\ifempty\xA4
+	\ifstart at i#1#2\@nil
+}
+\catcode`\@12
+a) \ifstart{abc}{bc}{vrai}{faux}\qquad
+b) \ifstart{abc}{ab}{vrai}{faux}\qquad
+c) \ifstart{ abc}{ }{vrai}{faux}\qquad
+d) \ifstart{abc}{}{vrai}{faux}\qquad
+e) \ifstart{}{a}{vrai}{faux}/
+
+Les deux derniers cas sont probl\xE9matiques. Il serait logique que l'avant-dernier soit vrai puisque \xAB\verb|abc|\xBB commence bien par un argument vide. Pour le dernier au contraire, il faudrait qu'il soit faux, car un argument vide ne contient pas le motif \xAB\verb|a|\xBB.
+
+Pour faire en sorte qu'un \verb|<motif>| vide donne toujours le code \verb|<vrai>|, il suffit \xE0 la ligne \no4 de tester si \verb|#2| est vide et ex\xE9cuter \xA7\firstoftwo si c'est le cas et appeler \verb-\ifstart at i- sinon :
+
+\centrecode-\ifempty{#2}\firstoftwo{\ifstart at i#1#2\@nil}-
+
+Si le \verb|<code>| est vide, l'appel \xE0 \verb-\ifstart at i- est \verb-\ifstart at i#2\@nil- et donc, l'argument d\xE9limit\xE9 \verb-##1- de \verb-\ifstart at i- est logiquement vide. On peut artificiellement le remplir en mettant un \idx\relax juste avant le \verb-#2- de la ligne 4. Cela donne le code :
+
+\showcode/\catcode`\@11
+\def\ifstart#1#2{%
+	\def\ifstart at i##1#2##2\@nil{\ifempty{##1}}%\xA4\xA7*\ifempty\xA4
+	\ifempty{#2}% si motif vide\xA4\xA7*\ifempty\xA4
+		\firstoftwo% ex\xE9cuter code "vrai"\xA4\xA7*\firstoftwo\xA4
+		{\ifstart at i#1\relax#2\@nil}% sinon, aller \xE0 la macro auxiliaire
+}
+\catcode`\@12
+a) \ifstart{abc}{bc}{vrai}{faux}\qquad
+b) \ifstart{abc}{ab}{vrai}{faux}\qquad
+c) \ifstart{ abc}{ }{vrai}{faux}\qquad
+d) \ifstart{abc}{}{vrai}{faux}\qquad
+e) \ifstart{}{a}{vrai}{faux}/
+\xA7*\ifstart[|)]\end{exercice}
+
+\subsection{Tester si un code se termine par un motif}
+Il est bien plus difficile de tester si un \verb|<code>| se termine par un \verb|<motif>|. Cela est d\xFB \xE0 la fa\xE7on qu'ont de fonctionner les arguments d\xE9limit\xE9s qui ne s'int\xE9ressent qu'\xE0 la \emph{premi\xE8re} occurrence d'un d\xE9limiteur et non pas \xE0 la derni\xE8re. Si nous souhaitons \xE9crire une macro \xA7\ifend[|(] dont la syntaxe est
+
+\centrecode-\ifend{<code>}{<motif>}{<vrai>}{<faux>}-
+
+\noindent nous allons devoir recourir \xE0 un algorithme r\xE9cursif.
+
+\begin{algo}
+	\item ajouter le \verb|<motif>| au d\xE9but du \verb|<code>| et dans le r\xE9sultat obtenu,
+	\item appeler \verb|<code>| ce qui est apr\xE8s la premi\xE8re occurrence du \verb|<motif>|;
+	\item si \verb|<code>| est vide ex\xE9cuter \verb|vrai|;
+	\item sinon
+	\begin{algo}
+		\item si \verb|<code>| contient le \verb|<motif>|, retourner en 2;
+		\item sinon, ex\xE9cuter \verb|faux|.
+	\end{algo}
+\end{algo}
+
+Le point \no1 sera l'appel initial \xE0 une macro auxiliaire r\xE9cursive \verb|\ifend at i| \xE0 argument d\xE9limit\xE9. Cette macro occupera les points suivants (de 2 \xE0 4).
+
+Traduisons cet algorithme en code \TeX{} et v\xE9rifions qu'il fonctionne sur quelques exemples. Le point 1 sera cod\xE9 de cette fa\xE7on :
+
+\centrecode-\ifend at i#2#1\@nil-
+
+La macro auxiliaire \verb-\ifend at i- va se charger, gr\xE2ce \xE0 son argument d\xE9limit\xE9, d'isoler ce qui se trouve apr\xE8s la premi\xE8re occurrence de \verb|<motif>|. Voici ce que sera son \idx{texte de param\xE8tre} :
+
+\centrecode-\def\if at end##1#2##2\@nil{...}-
+
+\noindent \xC0 l'int\xE9rieur de la macro \verb|\if at end|, il suffira de tester si \verb-##2- est vide auquel cas, \xA7\firstoftwo sera ex\xE9cut\xE9. Dans le cas contraire, il faudra tester avec \xA7\ifin si le \verb|##2| contient le \verb|<motif>| qui est \verb|#2| et appeler r\xE9cursivement \verb|\ifend at i| dans l'affirmative et ex\xE9cuter \xA7\secondoftwo sinon :
+
+\showcode/\catcode`\@11
+\def\ifend#1#2{%
+	\def\ifend at i##1#2##2\@nil{% ##2 = ce qui reste apr\xE8s le motif
+		\ifempty{##2}% si ##2 est vide\xA4\xA7*\ifempty\xA4
+			\firstoftwo% ex\xE9cuter l'argument "vrai"\xA4\defline\bbb\xA7*\firstoftwo\xA4
+			{\ifin{##2}{#2}% sinon, si ##2 contient le <motif>\xA4\xA7*\ifin\xA4
+				{\ifend at i##2\@nil}% appeler \ifend at i avec ce qui reste
+				\secondoftwo% sinon, ex\xE9cuter l'argument "faux"\xA4\xA7*\secondoftwo\xA4
+			}%
+	}%
+	\ifend at i#2#1\@nil% appelle la macro r\xE9cursive\xA4\defline\aaa\xA4
+}
+\catcode`\@12
+1) \ifend{abc de}{de}{vrai}{faux}\qquad
+2) \ifend{abd de }{de}{vrai}{faux}\qquad
+3) \ifend{abc de }{ }{vrai}{faux}\qquad
+4) \ifend{}{a}{vrai}{faux}\qquad
+5) \ifend{abc de}{}{vrai}{faux}/
+
+\begin{exercice}
+Expliquer pourquoi le code ci-dessus renvoie le contraire de ce que l'on attend aux cas \nos4 et 5 et proposer des solutions pour y rem\xE9dier.
+\solution
+Dans le cas o\xF9 le \verb|<code>| est vide (cas \no4), l'appel de la ligne \no\aaa{} devient
+
+\centrecode-\ifend at i a\@nil-
+
+\noindent et l'argument \verb|##2| de \verb|\ifend at i| qui se trouve apr\xE8s la premi\xE8re occurrence de \xAB\verb|a|\xBB est vide. Pour s'en pr\xE9munir, nous pouvons artificiellement meubler avec \idx\relax ce qui se trouve apr\xE8s cette premi\xE8re occurrence. L'appel \xE0 la ligne \no\aaa{} deviendrait donc :
+
+\centrecode-\ifend at i#2\relax#1\@nil-
+
+Pour le cas \no5, le \verb|<motif>| est vide, l'appel de la ligne \no\aaa{} est
+
+\centrecode-\ifend at i abc de\@nil-
+
+\noindent et le texte de param\xE8tre de \verb|\ifend at i| est \xAB\verb-\def\ifend at i##1##2\@nil{...}-\xBB ce qui signifie que l'argument \verb|##1| n'est plus un argument d\xE9limit\xE9 : il devient le premier argument (ici \xAB\verb|a|\xBB) et \verb|##2| est le reste jusqu'au \verb|\@nil| (c'est-\xE0-dire \xAB\verb|bc de|\xBB). Continuons \xE0 faire fonctionner la macro mentalement : le test \xA7\ifempty\verb|{##2}| est faux, le test suivant \xA7\ifin\verb|{##2}{#2}| est faux aussi puisque \verb|##2| est vide : la macro \xA7\secondoftwo va donc ex\xE9cuter le code \verb|faux|.
+
+Le meilleur rem\xE8de est sans doute de tester d\xE8s le premier appel (ligne \no\aaa) si \verb|#2| est vide, cas o\xF9 \xA7\firstoftwo doit \xEAtre ex\xE9cut\xE9.
+
+\showcode/\catcode`\@11
+\def\ifend#1#2{%
+	\def\ifend at i##1#2##2\@nil{% ##2 = ce qui reste apr\xE8s le motif
+		\ifempty{##2}% si ##2 est vide\xA4\xA7*\ifempty\xA4
+			\firstoftwo% ex\xE9cuter l'argument "vrai"\xA4\xA7*\firstoftwo\xA4
+			{\ifin{##2}{#2}% sinon, si ##2 contient le <motif>\xA4\xA7*\ifin\xA4
+				{\ifend at i##2\@nil}% appeler \ifend at i avec ce qui reste
+				\secondoftwo% sinon, ex\xE9cuter l'argument "faux"\xA4\xA7*\secondoftwo\xA4
+			}%
+	}%
+	\ifempty{#2}% si le motif est vide\xA4\xA7*\ifempty\xA4
+		\firstoftwo% ex\xE9cuter "vrai"\xA4\xA7*\firstoftwo\xA4
+		{\ifend at i#2\relax#1\@nil}% sinon, appelle la macro r\xE9cursive
+}
+\catcode`\@12
+1) \ifend{abc de}{de}{vrai}{faux}\qquad
+2) \ifend{abd de }{de}{vrai}{faux}\qquad
+3) \ifend{abc de }{ }{vrai}{faux}\qquad
+4) \ifend{}{a}{vrai}{faux}\qquad
+5) \ifend{abc de}{}{vrai}{faux}/
+\xA7*\ifend[|)]\end{exercice}
+
+\subsection{Remplacer un motif par un autre}\substin
+Nous allons maintenant construire une macro \xA7\substin[|(], capable de remplacer un \verb|<motif1>| par un \verb|<motif2>| dans un \verb|<code>| :
+
+\centrecode-\substin{<code>}{<motif1>}{<motif2>}-
+
+La m\xE9thode va consister \xE0 parcourir le \verb|<code>| un peu de la m\xEAme fa\xE7on que nous le faisions avec la macro \xA7\ifend. Voici l'algorithme :
+
+\begin{algo}
+	\item si le \verb|<code>| est vide, ne rien faire et fin du processus;
+	\item sinon
+	\begin{algo}
+		\item si le \verb|<code>| contient le \verb|<motif1>|, aller au point \no3;
+		\item sinon afficher le \verb|<code>| et fin du processus;
+	\end{algo}
+	\item afficher la partie du \verb|<code>| qui se trouve avant la 1\iere{} occurrence de \verb|<motif1>|;
+	\item afficher \verb|<motif2>|;
+	\item retourner au point \no1 en appelant \verb|<code>| ce qui se trouve apr\xE8s \verb|<motif1>|.
+\end{algo}
+
+Les points \nos1 et 2 vont \xEAtre effectu\xE9s par une macro auxiliaire dont le seul argument non d\xE9limit\xE9 sera le 
+\verb|<code>| en cours d'examen. Les points \nos3 \xE0 5 seront d\xE9volus \xE0 une autre macro auxiliaire qui elle, sera \xE0 argument d\xE9limit\xE9 puisqu'il faut s\xE9parer ce qui se trouve avant et apr\xE8s le \verb|<motif1>|. Voici ce que cela donne en \idx{pseudocode} :
+
+\begingroup
+\numalgofalse
+\def\algoleftskip{.1\hsize}
+\def\algorightskip{.1\hsize}\label{algo2}
+\algorithm[\#]{Remplacer toutes les occurrences d'un motif}|
+macro ~substin~#1#2#3% #1=<code>, #2=<motif1>, #3=<motif2>
+	macro ~substin at i~##1
+		~si~ ##1 est vide
+			relax% ne rien faire
+		~sinon~
+			~si~ ##1 contient #3
+				~substin at ii~##1 at nil% appeler la macro \xE0 argument d\xE9limit\xE9s
+			~sinon~
+				##1% afficher le <code>
+			~finsi~
+		~finsi~
+	~fin~\medbreak
+	macro ~substin at ii~##1#2##2 at nil% ##1 et ##2=ce qui est avant/apr\xE8s <motif1>
+		afficher "##1#3"
+		appeler ~substin at i~(##2)% puis recommencer avec le code qui reste
+	~fin~\medbreak
+	appeler ~substin at i~(#1)% engage le processus
+~fin~|
+\endgroup
+
+La traduction de ce \idx{pseudocode} en \TeX{} ne pose pas de probl\xE8me particulier :
+
+\showcode/\catcode`\@11
+\def\substin#1#2#3{%
+	\def\substin at i##1{%
+		\ifempty{##1}% si le <code> est vide\xA4\xA7*\ifempty\xA4
+			\relax% ne rien faire -> fin du processus
+			{\ifin{##1}{#2}% sinon, si le <code> contient <motif1>\xA4\xA7*\ifin\xA4
+				{\substin at ii##1\@nil}% appeler la macro \xE0 argument d\xE9limit\xE9s
+				{##1}% sinon, afficher le <code>
+			}%
+	}%
+	\def\substin at ii##1#2##2\@nil{%
+		##1#3% afficher ##1 et #3 (qui est <motif2>)
+		\substin at i{##2}% et recommencer avec ce qui reste
+	}%
+	\substin at i{#1}%
+}
+\catcode`\@12
+a) \substin{abracadabra}{a}{A}\qquad
+b) \substin{abracadabra}{x}{W}\qquad
+c) \substin{abracadabra}{br}{}\qquad
+d) \substin{1\relax3}\relax{222}\qquad/\xA7*\substin[|)]
+
+\begin{exercice}
+Modifier cette macro en une macro \xA7\substtocs[|(] pour qu'elle n'affiche pas le r\xE9sultat, mais le mette dans le texte de remplacement d'une \verb|\<macro>| dont l'utilisateur pourra choisir le nom :
+
+\centrecode-\substtocs\<macro>{<code>}{motif1}{motif2}-
+
+\solution
+Au lieu d'afficher des morceaux de code, il faudra les ajouter au texte de remplacement d'une macro charg\xE9e de collecter le code r\xE9sultant de ces substitutions. Pour ajouter du code au texte de remplacement d'une macro, \xA7\addtomacro, programm\xE9e \xE0 la page~\pageref{addtomacro} sera utile.
+
+\showcode/\catcode`\@11
+\def\substtocs#1#2#3#4{%
+	\def\substtocs at i##1{%
+		\ifempty{##1}% si le <code> est vide\xA4\xA7*\ifempty\xA4
+			\relax% ne rien faire -> fin du processus
+			{\ifin{##1}{#3}% sinon, si le <code> contient <motif1>\xA4\xA7*\ifin\xA4
+				{\substtocs at ii##1\@nil}% appeler la macro \xE0 argument d\xE9limit\xE9s
+				{\addtomacro#1{##1}}% sinon, ajouter le <code>\xA4\xA7*\addtomacro\xA4
+			}%
+	}%
+	\def\substtocs at ii##1#3##2\@nil{%
+		\addtomacro#1{##1#4}% ajouter ##1#4\xA4\xA7*\addtomacro\xA4
+		\substtocs at i{##2}% et recommencer avec ce qui reste
+	}%
+	\let#1=\empty% initialise la macro \xE0 vide\xA4\idx*\empty\xA4
+	\substtocs at i{#2}%
+}
+\catcode`\@12
+\substtocs\foo{abracadabra}{a}{A}\meaning\foo\par
+\substtocs\foo{abracadabra}{x}{W}\meaning\foo\par
+\substtocs\foo{abracadabra}{br}{}\meaning\foo\par
+\substtocs\foo{1\relax3}\relax{222}\meaning\foo\par
+\substtocs\foo{\ifnum1=2 test vrai\fi}{2}{1}\meaning\foo/
+\end{exercice}\xA7*\substtocs[|)]
+
+\begin{exercice}\label{exo.majuscules}
+\xC9crire une macro \xA7\majmot[|(]\verb|{<phrase>}| qui met en majuscule tous les mots de la \verb|phrase|.
+\solution
+Pour que \xA7\majmot effectue son travail, dans la \verb|<phrase>|, chaque espace doit \xEAtre remplac\xE9 par \xAB\verb*| \majuscule|\xBB, o\xF9 la macro \xA7\majuscule lit un argument (qui sera la lettre du mot suivant) et la met en majuscule. En coulisses, nous utiliserons la primitive \idx\uppercase.
+
+Nous allons mettre \xA7\substin \xE0 contribution pour effectuer ces remplacements, en ayant pris soin de mettre \xA7\majuscule tout au d\xE9but de la phrase afin de traiter la premi\xE8re lettre du premier mot.
+
+\showcode/\def\majuscule#1{\uppercase{#1}}\xA4\idx*\uppercase\xA7*\majuscule\xA4
+\def\majmot#1{\substin{\majuscule#1}{ }{ \majuscule}}\xA4\xA7*\substin\xA7*\majuscule\xA4
+\majmot{un petit texte}\par
+\majmot{Un grand texte sans importance}/
+
+Conclusion : \xE7a ne fonctionne pas du tout !
+
+Une petite analyse montre que tout vient de la fa\xE7on dont est faite la substitution et il faut revenir au code de \xA7\substin :
+
+\begingroup
+\renewcommand*\indentcodeactivechars[1]{%
+	\defactive\^^M{\par\hspace{#1}}%
+	\defactive\^^I{{ }{ }}% tab = 4 espaces
+	\catcode`\\xA4=13
+	\begingroup
+		\lccode`\~`\\xA4\relax
+		\lowercase{\endgroup\long\def~##1~}{%
+			\begingroup
+				\catcode`\{=1 \catcode`\}=2 \catcode`\#=6 \catcode`\\=0 \catcode`\$=3
+				\catcode`\f=11
+				\endlinechar=-1
+				\scantokens{##1}%
+			\endgroup
+			}% \xE9chappement \xA4...\xA4
+	\footnotesize
+}\indencodenumtrue
+\indentcode/\def\substin#1#2#3{%\xA4\xA7*\substin\xA4
+	\def\substin at i##1{%
+		\ifempty{##1}% si le code est vide\xA4\xA7*\ifempty\xA4
+			\relax% ne rien faire -> fin du processus
+			{\ifin{##1}{#2}% sinon, si le code contient motif1\xA4\xA7*\ifin\xA4
+				{\substin at ii##1\@nil}% appeler la macro \xE0 argument d\xE9limit\xE9s
+				{##1}% sinon, afficher le code
+			}%
+	}%
+	\def\substin at ii##1#2##2\@nil{%
+		##1#3% afficher ##1 et #3 (qui est <motif2>)
+		\substin at i{##2}% et recommencer avec ce qui reste
+	}%
+	\substin at i{#1}%
+}/\endgroup
+
+Constatons \xE0 ligne \no11 que le code \verb|#2| est substitu\xE9 par le motif \verb|#3| donc, \verb|##1#3| est ex\xE9cut\xE9 par \TeX{} dans la foul\xE9e. C'est de cette ex\xE9cution \emph{au fur et \xE0 mesure} que vient le probl\xE8me. Ici en effet, le motif de substitution \verb|#3| est \xAB\verb*| \majsucule|\xBB. Notre processus \xE9choue parce que lors de l'ex\xE9cution au fur et \xE0 mesure, la macro \xA7\majuscule va lire son argument qui est \verb|\substin at i| de la ligne \no12. Cet argument sera trait\xE9 par \idx\uppercase qui le laisse intact puisque \idx\uppercase n'a aucun effet sur les s\xE9quences de contr\xF4le. Le code ci-dessus ne produit donc aucun effet.
+
+Nous allons nous en sortir en utilisant la macro \xA7\substtocs de fa\xE7on \xE0 stocker le code obtenu dans une macro temporaire \verb|\temp| que nous afficherons \xE0 la toute fin du processus, avant de sortir du groupe semi-simple dans lequel elle a \xE9t\xE9 cr\xE9\xE9e :
+
+\showcode/\def\majuscule#1{\uppercase{#1}}\xA4\idx*\uppercase\xA7*\majuscule\xA4
+\def\majmot#1{%
+	\begingroup\xA4\idx*\begingroup\xA4
+		\substtocs\temp{\majuscule#1}{ }{ \majuscule}%\xA4\xA7*\substtocs\xA7*\majuscule\xA4
+		\temp% ex\xE9cute la macro temporaire
+	\endgroup\xA4\idx*\endgroup\xA4
+}
+\majmot{un petit texte}\par
+\majmot{Un grand texte Sans importance}/
+
+La le\xE7on \xE0 retenir ici est que faire ex\xE9cuter par \TeX{} de morceaux de code dans une macro r\xE9cursive n'est pas \xE9quivalent \xE0 les mettre tous dans une s\xE9quence de contr\xF4le que l'on ex\xE9cute en une fois \xE0 la fin.\xA7*\majmot[|)]
+\end{exercice}
+
+\begin{exercice}
+\xC9crire une macro \xA7\cnttimes[|(]\label{cnttimes}\verb|{<code>}{<motif>}| qui affiche combien de fois le \verb|<motif>| est contenu dans le \verb|<code>|.
+\solution
+Nous allons proc\xE9der comme dans \xA7\substtocs. La macro chapeau initialisera un compteur \xE0 0 et passera la main \xE0 une macro auxiliaire, charg\xE9e de l'incr\xE9menter \xE0 chaque fois que le motif sera rencontr\xE9 :
+
+\showcode/\catcode`\@11
+\newcount\cnt at occ\xA4\idx*\newcount\xA4
+\def\cnttimes#1#2{%\xA4\xA7*\cnttimes\xA4
+	\def\cnttimes at i##1{%
+		\ifempty{##1}% si le <code> est vide\xA4\xA7*\ifempty\xA4
+			{\number\cnt at occ}% afficher le nombre d'occurrences\xA4\idx*\number\xA4
+			{\ifin{##1}{#2}% sinon, si le <code> contient <motif1>\xA4\xA7*\ifin\xA4
+				{\cnttimes at ii##1\@nil}% appeler la macro \xE0 argument d\xE9limit\xE9s
+				{\number\cnt at occ}% sinon, afficher le nombre d'occurrences
+			}%
+	}%
+	\def\cnttimes at ii##1#2##2\@nil{%\xA4\idx*\advance\xA4
+		\advance\cnt at occ1
+		\cnttimes at i{##2}% et recommencer avec ce qui reste
+	}%
+	\cnt at occ=0 % initialise le compteur
+	\cnttimes at i{#1}%
+}
+\catcode`\@12
+a) \cnttimes{abracadabra}{a}\qquad
+b) \cnttimes{abracadabra}{ra}\qquad
+c) \cnttimes{abracadabra}{w}\qquad
+d) \cnttimes{abc def ghijk l }{ }\qquad
+e) \cnttimes{\ifnum1=2 vrai\else faux\fi}{\ifnum}\xA4\xA7*\cnttimes\xA4/\xA7*\cnttimes[|)]
+
+Juste pour le plaisir de se compliquer la vie, essayons de modifier la macro en \xA7\cnttimestocs[|(] pour qu'elle r\xE9ponde aux contraintes suivantes :
+
+\begin{enumerate}
+	\item ne pas utiliser de compteur;
+	\item n'\xE9crire qu'une seule macro int\xE9rieure au lieu de deux;
+	\item stocker le r\xE9sultat dans une macro sp\xE9cifi\xE9e par l'utilisateur.
+\end{enumerate}
+
+Si nous nous interdisons l'utilisation d'un compteur, nous devrons recourir \xE0 la primitive \idx\numexpr pour remplacer \idx\advance afin d'incr\xE9menter le nombre d'it\xE9rations. Il est \xE9videmment possible de stocker le nombre d'it\xE9rations dans une s\xE9quence de contr\xF4le, mais dans ce cas, se priver d'un compteur pour basculer vers une macro n'a pas vraiment de sens, autant conserver un compteur. Il est plus original de stocker le nombre d'it\xE9rations dans un argument qui s'ajoutera \xE0 ceux de la macro r\xE9cursive \verb|\cnttimes at i| vue dans le code pr\xE9c\xE9dent. Pour pouvoir facilement incr\xE9menter cet argument (qui implique le 1-d\xE9velopper) avant de lancer l'appel r\xE9cursif, il est judicieux de le placer comme premier argument. L'id\xE9e la plus pratique est donc d'ajouter cet argument (et de le d\xE9limiter par un \verb|\@nil|) avant ceux de \verb-\cnttimes at ii-. La macro r\xE9cursive \verb|\cnttimestocs at i| aura donc le texte de param\xE8tre suivant :
+
+\centrecode-\def\cnttimestocs at i##1\@nil##2#2##3\@nil{...}-
+
+\noindent Il faudra sp\xE9cifier \xAB\verb|0|\xBB comme argument \verb|##1| lors du premier appel.
+
+Ensuite, comme cette macro r\xE9cursive \xE0 est \xE0 argument d\xE9limit\xE9 par le \verb|<motif>|, elle \emph{doit} recevoir un \verb|<code>| qui contient ce \verb|<motif>|. Il est donc n\xE9cessaire de tester la pr\xE9sence de ce \verb|<motif>| lors du premier appel et \xE9galement \xE0 l'int\xE9rieur de la macro r\xE9cursive avant qu'elle ne s'appelle elle-m\xEAme avec le \verb|<code>| restant.
+
+\showcode|\catcode`\@11
+\long\def\cnttimestocs#1#2#3{% #3=macro recevant le r\xE9sultat\xA4\xA7*\cnttimestocs\xA4
+	\long\def\cnttimestocs at i##1\@nil##2#2##3\@nil{%
+		% ##1=nb d'occurrences rencontr\xE9es jusqu'alors
+		% ##2 et ##3=ce qui est avant/apr\xE8s le <motif>
+		\ifin{##3}{#2}% si le <motif> est dans ce qui reste\xA4\xA7*\ifin\xA4
+			{\expandafter\cnttimestocs at i% appeler la macro r\xE9cursive
+				\number\numexpr##1+1\relax\@nil% avec une occurrence de plus\xA4\idx*\number\idx*\numexpr\xA4
+				##3\@nil% et ce qui reste
+			}%
+			{\edef#3{\number\numexpr##1+1\relax}}% sinon, stocker 1 occurrence de plus dans #3
+	}%
+	\ifin{#1}{#2}% si le <motif> est dans le <code>\xA4\xA7*\ifin\xA4
+		{\cnttimestocs at i 0\@nil#1\@nil}% appeler la macro r\xE9cursive avec 0 occurrence
+		{\def#3{0}}% sinon, mettre 0 dans #3
+}
+\catcode`\@12
+a) \cnttimestocs{abracadabra}{a}\foo \meaning\foo\qquad
+b) \cnttimestocs{abracadabra}{ra}\foo \meaning\foo\qquad
+c) \cnttimestocs{abracadabra}{w}\foo \meaning\foo\qquad
+d) \cnttimestocs{abc def ghijk l }{ }\foo \meaning\foo\qquad
+e) \cnttimestocs{\ifnum1=2 vrai\else faux\fi}{\ifnum}\foo \meaning\foo|
+\xA7*\cnttimestocs[|)]\end{exercice}
+
+\subsection{Substitutions successives}
+Nous allons maintenant \xE9crire une macro \xA7\multisubst[|(], g\xE9n\xE9ralisation de la macro \xA7\substin o\xF9 nous pourrons sp\xE9cifier plusieurs substitutions successives :
+
+\centrecode-\multisubst{<code>}{{<motif1>}{<motif2>}{<motif3>}{<motif4>}{<motif5>}...}-
+
+\noindent Cette macro substituera toutes les occurrences de \verb|<motif1>| par \verb|<motif2>| puis toutes celles de \verb|<motif3>| par \verb|<motif4>| et ainsi de suite jusqu'\xE0 ce que la liste des substitutions soit vide dans le deuxi\xE8me argument. Les motifs utilis\xE9s dans la substitution seront donc lus par \emph{paires}. L'id\xE9e est de se servir de la macro \xA7\substin pr\xE9c\xE9demment \xE9crite en lui envoyant comme second et troisi\xE8me argument les motifs de substitution pris deux par deux dans la liste. Comme un espace non entour\xE9 d'accolades est ignor\xE9 en tant qu'argument, les motifs peuvent \xEAtre group\xE9s par paires \emph{s\xE9par\xE9es par un espace} dans la liste des motifs afin d'en am\xE9liorer la lisibilit\xE9.
+
+\showcode/\catcode`\@11
+\def\multisubst#1#2{%
+	\def\subst at code{#1}% stocke le <code>
+	\multisubst at i#2\@nil% appelle la macro r\xE9cursive avec la liste de motifs
+}
+
+\def\multisubst at i#1#2#3\@nil{% #1 et #2=paire de motifs  #3=motifs restants
+	\expandafter\substtocs\expandafter\subst at code\expandafter% 1-d\xE9veloppe\xA4\xA7*\substtocs\xA4
+		{\subst at code}{#1}{#2}% le <code> et effectue la substitution en cours
+	\ifempty{#3}% si la liste des motifs est vide\xA4\xA7*\ifempty\xA4
+		\subst at code% ex\xE9cuter le <code> obtenu
+		{\multisubst at i#3\@nil}% recommencer avec les motifs qui restent
+}
+\catcode`\@12
+1) \multisubst{abracadabra}{aA rR}\par
+2) \multisubst{Ce texte devenu \`a peine reconnaissable montre que le\xA4\defline\aaa\xA4
+   r\'esultat contient des sonorit\'es catalanes, corses ou grecques
+   assez inattendues.}{a{AA} ya uy ou io ei {AA}e}/
+
+La macro chapeau \verb|\multisubst| de la ligne \no2 se contente de lire le \verb|<code>| et l'assigne \xE0 la macro \verb|\subst at code| avant de passer la main \xE0 la v\xE9ritable macro r\xE9cursive \verb|\multisubt at i|, \xE0 argument d\xE9limit\xE9. La liste des motifs de substitutions est pass\xE9e comme argument pour s'\xE9tendre jusqu'au \verb|\@nil|. Les arguments non d\xE9limit\xE9s \verb|#1| et \verb|#2| deviennent les deux motifs de substitution de l'it\xE9ration en cours tandis que \verb|#3| est la liste des paires restantes.
+
+Le cas \no2 des lignes \nos\aaa{} \xE0 \number\numexpr\aaa+2\relax{} traite d'une fa\xE7on diff\xE9rente le probl\xE8me de la permutation circulaire des voyelles d\xE9j\xE0 r\xE9solu \xE0 la page~\pageref{permutation.voyelles}. On ne touche plus \xE0 aucun code de cat\xE9gorie, mais on effectue tour \xE0 tour les substitutions d\xE9sir\xE9es. La m\xE9thode est cependant \emph{lente}, car l'argument est ici un texte assez long et celui-ci sera parcouru par \xA7\multisubst autant de fois qu'il y a de substitutions \xE0 faire, c'est-\xE0-dire 7 fois. La \xAB propret\xE9 \xBB que l'on gagne \xE0 ne pas modifier les codes de cat\xE9gorie se paie en lenteur.
+\grandsaut
+
+Au-del\xE0 ce ce d\xE9faut li\xE9 \xE0 la m\xE9thode utilis\xE9e, le code pr\xE9sente une autre redondance : chaque paire est lue \emph{plusieurs fois}. Elle est lue une premi\xE8re fois par la macro chapeau \verb|\multisubst| puisqu'elle lit toutes les paires. Par la suite, \xE0 chaque it\xE9ration, la macro r\xE9cursive \verb|\multisubst at i| lit (et mange) la premi\xE8re paire de son argument, mais lit \emph{aussi que la totalit\xE9 des paires restantes}. La totalit\xE9 des paires est donc lue deux fois : une fois par la macro chapeau et une fois par la macro r\xE9cursive lors de la premi\xE8re it\xE9ration (qui ensuite supprime la paire \no1). \xC0 la 2\ieme{} it\xE9ration, la macro r\xE9cursive lit la totalit\xE9 des paires restantes et supprime la paire \no2, etc. Ainsi, s'il y a $n$ paires, la premi\xE8re est lue 2 fois, la 2\ieme{} est lue 3 fois, et ainsi de suite jusqu'\xE0 la $n$\ieme{} qui est lue $n+1$ fois.
+
+Il s'agit donc de changer de m\xE9thode afin de limiter le nombre de lectures des paires. Envisageons le sc\xE9nario suivant : 
+
+\begin{itemize}
+ \item lire la liste de toutes les paires une fois afin de les transmettre \xE0 la macro r\xE9cursive en les faisant suivre d'une paire sp\xE9ciale, constitu\xE9e de deux arguments sp\xE9ciaux;
+ \item cette macro r\xE9cursive, au lieu de lire tous les arguments, n'en lit que deux : pour savoir si elle doit les prendre comme une paire de motifs ou comme condition d'arr\xEAt, il faut qu'elle les teste et les compare aux arguments sp\xE9ciaux;
+ \item si le test est positif, cela signifie que la fin de la liste des couples de motifs a \xE9t\xE9 compl\xE8tement lue et que la fin du processus doit \xEAtre ex\xE9cut\xE9e;
+ \item dans le cas d'un test n\xE9gatif, la substitution est ex\xE9cut\xE9e et la macro s'appelle elle m\xEAme pour une nouvelle it\xE9ration.
+\end{itemize}
+
+Cette fa\xE7on de proc\xE9der implique que chaque paire est lu exactement deux fois; une fois par la macro chapeau et une fois par la macro r\xE9cursive.
+
+Un dernier d\xE9tail doit \xEAtre d\xE9cid\xE9 : que sont des arguments \emph{sp\xE9ciaux}? Ce sont des arguments qui ne sont pas susceptibles d'\xEAtre un des deux motifs. Tout est imaginable, mais il semble assez s\xFBr de prendre un \idx{quark} tant ce genre de macro est improbable dans une liste de motifs de substitution. Voici comment modifier le code :
+
+\showcode/\catcode`\@11
+\def\quark{\quark}\xA4\xA7*\quark\xA4
+
+\def\multisubst#1#2{% #1 = <code>   #2 = <liste des paires>
+	\def\subst at code{#1}% stocke le <code>
+	\multisubst at i#2\quark\quark% appelle la macro r\xE9cursive avec \xA4\xA7*\quark\xA4
+	                           % 2 arguments sp\xE9ciaux en fin de liste
+}
+
+\def\multisubst at i#1#2{% #1#2 = paire de motifs en cours
+	\def\arg at a{#1}% stocke le <motif1> dans une macro
+	\ifx\arg at a\quark% si le motif sp\xE9cial est atteint\xA4\xA7*\quark\xA4
+		\expandafter\subst at code% ex\xE9cuter le code obtenu
+	\else
+		\expandafter\substtocs\expandafter\subst at code\expandafter% 1-d\xE9veloppe\xA4\xA7*\substtocs\xA4
+			{\subst at code}{#1}{#2}% le <code> et effectue la substitution en cours
+		\expandafter\multisubst at i% puis lis la paire de motifs suivants
+	\fi
+}
+\catcode`\@12
+\multisubst{abracadabra}{aA rR}\par
+\multisubst{Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des
+  sonorit\'es catalanes, corses ou grecques assez inattendues.}{a{AA} ya uy ou io ei {AA}e}/\xA7*\multisubst[|)]
+
+\label{lire.arguments}\begin{regle}[M\xE9thode de programmation]
+	Lorsqu'une liste d'arguments cons\xE9cutifs doit \xEAtre lue au fur et \xE0 mesure par une macro r\xE9cursive, deux m\xE9thodes de lecture sont envisageables. Elles ont en commun une premi\xE8re lecture de tous les arguments afin de les passer \xE0 la macro r\xE9cursive et c'est cette derni\xE8re qui a deux fa\xE7ons de fonctionner :
+
+	\begin{enumerate}
+		\item lire la totalit\xE9 des arguments restants \xE0 chaque it\xE9ration, utiliser ceux qui sont utiles \xE0 l'it\xE9ration en cours et recommence1r avec tous les arguments restants. S'arr\xEAter lorsque la liste d'arguments restants est vide;
+		\item ne lire \emph{que} les arguments utiles \xE0 l'it\xE9ration en cours, les utiliser et recommencer. S'arr\xEAter lorsque l'un des arguments lus est \xE9gal \xE0 un argument sp\xE9cifique pr\xE9alablement plac\xE9 en fin de liste par la macro chapeau.
+	\end{enumerate}
+	\end{regle}
+
+Il est inutile de dire qu'un programmeur rigoureux choisit de pr\xE9f\xE9rence la deuxi\xE8me m\xE9thode m\xEAme si souvent, le nombre d'arguments \xE0 lire est peu \xE9lev\xE9 auquel cas la premi\xE8re m\xE9thode est parfaitement acceptable.\tidx*[|)]{ifx}
+
+\section{Autres tests}
+\subsection{Pseudotests et variables bool\xE9ennes}\idx*[|(]{pseudotest}
+\TeX{} dispose des pseudotests \tidx{iftrue} et \tidx{iffalse}, le premier est toujours vrai et le second toujours faux. Bien qu'elles en partagent la syntaxe et les subtilit\xE9s de d\xE9veloppement, ces primitives n'effectuent pas de tests. Cependant, nous allons le voir un peu plus bas, elles n'en sont pas moins utiles.
+
+\showcode/\iftrue foobar\else ceci n'est jamais lu par \TeX\fi\par
+\iffalse ceci n'est jamais lu par \TeX\else foobar\fi/
+
+On peut bien s\xFBr rendre une macro \idx\let-\xE9gale \xE0 \tidx{iftrue} ou \tidx{iffalse} pour, au choix, disposer d'une macro simulant un test toujours vrai ou toujours faux. C'est d'ailleurs exactement ce que fait la macro de plain-\TeX{} \idx\newif\verb|<macro>| qui construit 3 macros qui ont un comportement identique \xE0 celui de variables \xAB bool\xE9ennes \xBB que l'on trouve dans d'autres langages.
+
+Ainsi, si nous \xE9crivons \idx\newif\verb|\ifbar| alors, 3 s\xE9quences de contr\xF4le seront cr\xE9\xE9es :
+\begin{itemize}
+	\item \verb|\bartrue|  qui rend \verb|\ifbar| \idx\let-\xE9gale \xE0 \tidx{iftrue} ;
+	\item \verb|\barfalse| qui rend \verb|\ifbar| \idx\let-\xE9gale \xE0 \tidx{iffalse} ;
+	\item \verb|\ifbar| qui tient lieu de \tidx{iftrue} ou \tidx{iffalse} selon la \xAB valeur bool\xE9enne \xBB qui lui aura \xE9t\xE9 donn\xE9e par l'une des deux premi\xE8res macros.
+\end{itemize}
+
+\showcode/\newif\ifhomme\xA4\idx*\newif\xA4
+\def\debutlettre{Ch\ifhomme er Monsieur\else \xE8re Madame\fi}%
+
+\hommetrue
+\debutlettre
+\medbreak\xA4\idx*\medbreak\xA4
+
+\hommefalse
+\debutlettre/
+
+Le \idx[!plain-\TeX]{format} plain-\TeX{} fait en sorte que lorsqu'on \xE9crit \idx\newif\verb|\<nom>|, le \verb|<nom>| commencer \emph{obligatoirement} par \xAB\verb|if|\xBB. Il est int\xE9ressant de noter que \LaTeX{} r\xE9-impl\xE9mente la macro \idx\newif en autorisant le \verb|<nom>| \xE0 commencer par deux caract\xE8res quelconques qui seront enlev\xE9s lorsque \verb|\<nomtrue>| ou \verb|\<nomfalse>| sont cr\xE9es.
+
+\begin{regle}
+Les \idx{pseudotest}s \tidx{iftrue} et \tidx{iffalse} n'effectuent aucun test et donc n'admettent aucun argument. Ils sont respectivement toujours vrai et toujours faux. En d\xE9pit de ce caract\xE8re invariable, ils se comportent comme n'importe quel test, notamment en ce qui concerne l'\xE9ventuelle pr\xE9sence du \tidx{else} et celle, obligatoire, du \tidx{fi}.
+
+La macro \idx\newif, suivie d'une macro \verb|\if<nom>| cr\xE9e 3 nouvelles macros dont le comportement est identique \xE0 celui des variables bool\xE9ennes. Le test \verb|\if<nom>| sera vrai si la macro \verb|\<nom>true| a \xE9t\xE9 ex\xE9cut\xE9e auparavant et sera faux si c'est la macro \verb|\<nom>false|.
+\end{regle}\idx*[|)]{pseudotest}
+
+\subsection{Le test \texttt{\textbackslash ifcat}}\tidx*[|(]{ifcat}
+Le test \verb|\ifcat<token1><token2>| compare les codes de cat\xE9gorie des deux tokens qui le suivent imm\xE9diatement. Ce test se comporte un peu comme \tidx{ifnum} en ce sens qu'il lance un d\xE9veloppement maximal \emph{avant} de faire le test. Sans action visant \xE0 emp\xEAcher le d\xE9veloppement (utilisation de \idx\noexpand ou \idx\unexpanded), le test compare donc les deux premiers tokens non d\xE9veloppables r\xE9sultant du d\xE9veloppement maximal.
+
+Il faut savoir que pour \verb|\ifcat|, un token de type s\xE9quence de contr\xF4le est vu comme ayant un code de cat\xE9gorie \xE9gal \xE0 16. Cette 17\ieme{} cat\xE9gorie, sp\xE9cifique au test \verb|\ifcat|, vient s'ajouter aux 16 autres cat\xE9gories d\xE9j\xE0 existantes pour la primitive \idx\catcode. En revanche, si une s\xE9quence de contr\xF4le ou un caract\xE8re actif a \xE9t\xE9 pr\xE9alablement rendu \idx\let-\xE9gal \xE0 un \verb|<token>|, \verb|\ifcat| prend en compte le code de cat\xE9gorie du \verb|<token>|.
+
+\showcode/\catcode`\*=13 \catcode`\+=13 % "*" et "+" sont actifs
+1) \def*{xyz}\def+{abc}% d\xE9finit les caract\xE8res actifs
+   \ifcat *+vrai\else faux\fi\qquad \xA4\tidx*{ifcat}\xA4
+2) \ifcat \noexpand *\noexpand +vrai\else faux\fi\qquad\xA4\idx*\noexpand\xA4
+3) \def\foo{foobar}%
+   \ifcat \noexpand\foo\relax vrai\else faux\fi\qquad% \foo et \relax sont vus \xE9gaux   \xA4\idx*\noexpand\xA4
+4) \ifcat = vrai\else faux\fi\qquad% "=" et " " n'ont pas le m\xEAme catcode
+5) \ifcat _^vrai\else faux\fi\qquad% "_" et "^" n'ont pas le m\xEAme catcode
+6) \let\foo=&
+   \ifcat &\foo vrai\else faux\fi% "&" et \foo (let-\xE9gal \xE0 "&") sont vus \xE9gaux\xA4\tidx*{ifcat}\xA4/
+
+Ce qui arrive lors du test \no1 est facilement compr\xE9hensible : le caract\xE8re actif \xAB\verb-*-\xBB est d\xE9velopp\xE9 au maximum pour donner \xAB\verb-xyz-\xBB. Le test \verb|\ifcat| comparera donc les deux premiers tokens issus de ce d\xE9veloppement, \xAB\verb-x-\xBB et \xAB\verb-y-\xBB, et comme ils ont le m\xEAme catcode, le test sera vrai et tout ce qui est avant le \tidx{else} sera ex\xE9cut\xE9. Le \xAB\verb|z|\xBB restant va \xEAtre dirig\xE9 vers l'affichage. Ensuite, le caract\xE8re actif \xAB\verb|+|\xBB va se d\xE9velopper et afficher \xAB\verb|abc|\xBB. Enfin, \xAB\verb|vrai|\xBB sera affich\xE9. On obtient bien l'affichage \xAB\verb|zabcvrai|\xBB.
+
+Le \idx\noexpand du test \no3 bloque le d\xE9veloppement de la macro \verb|\foo| et la comparaison qui est faite est bien entre les catcodes de \xAB\verb-\foo-\xBB et \xAB\verb-\relax-\xBB.
+
+\begin{regle}
+Le test \verb|\ifcat| lance le d\xE9veloppement maximal et d\xE8s qu'il obtient deux tokens non d\xE9veloppables (ou dont le d\xE9veloppement est bloqu\xE9 par \idx\noexpand ou \idx\unexpanded), il effectue la comparaison des codes de cat\xE9gorie.
+
+Si un token test\xE9 par \verb|\ifcat| est une s\xE9quence de contr\xF4le ou un caract\xE8re actif rendu \idx\let-\xE9gal \xE0 un \verb|<token>|, \verb|\ifcat| prend en compte le code de cat\xE9gorie du \verb|<token>|.
+
+Si un token test\xE9 par \verb|\ifcat| est une s\xE9quence de contr\xF4le, son code de cat\xE9gorie est vu \xE9gal \xE0 16.
+\end{regle}
+
+\begin{exercice}\label{ifcs}
+\xC9crire une macro \xA7\ifcs[|(], de syntaxe
+
+\centrecode|\ifcs<token>{<vrai>}{<faux>}|
+
+qui teste si le \verb|<token>| est une s\xE9quence de contr\xF4le au sens de \verb|\ifcat|. Selon l'issue du test, \verb|<vrai>| ou \verb|<faux>| seront ex\xE9cut\xE9s.
+\solution
+La comparaison sera faite entre le \verb|<token>| dont on aura bloqu\xE9 le d\xE9veloppement et \idx\relax. Voici le code :
+
+\showcode/\catcode`\@11
+\def\ifcs#1{%\xA4\xA7*\firstoftwo\xA7*\secondoftwo\idx*\noexpand\xA4
+	\ifcat\noexpand#1\relax\expandafter\firstoftwo
+	\else                  \expandafter\secondoftwo
+	\fi
+}
+\catcode`\@12
+1) \def\foo{bar}\ifcs\foo{vrai}{faux}\qquad
+2) \ifcs\def{vrai}{faux}\qquad
+3) \ifcs A{vrai}{faux}\qquad
+\catcode`\*=13 
+4) \let*=W \ifcs*{vrai}{faux}\qquad
+5) \let*=\relax \ifcs*{vrai}{faux}\qquad
+6) \let\foo=A \ifcs\foo{vrai}{faux}\qquad
+7) \ifcs\bgroup{vrai}{faux}/
+
+Remarquons aux cas \nos5, 6 et 7 que si l'on s'en tient \xE0 la vraie d\xE9finition d'une s\xE9quence de contr\xF4le (suite de caract\xE8res qui commence par le caract\xE8re d'\xE9chappement), le test \xA7\ifcs que nous avons \xE9crit n'est pas satisfaisant.
+\end{exercice}\xA7*\ifcs[|)]\tidx*[|)]{ifcat}
+
+\subsection{Le test \texttt{\textbackslash if}}\tidx*[|(]{if}
+Le test \verb|\if| est en tous points semblable au test \verb|\ifcat| sauf que ce sont les codes de \emph{caract\xE8re} des deux tokens qui sont compar\xE9s.
+
+\begin{regle}
+Le test \verb|\if| instaure un d\xE9veloppement maximal et d\xE8s qu'il obtient deux tokens non d\xE9veloppables (ou dont le d\xE9veloppement est bloqu\xE9 par \idx\noexpand ou \idx\unexpanded), il effectue la comparaison de leurs codes de caract\xE8re.
+
+Si un token test\xE9 par \verb|\if| est une s\xE9quence de contr\xF4le ou un caract\xE8re actif rendu \idx\let-\xE9gal \xE0 un \verb|<token>|, \verb|\if| prend en compte le code de caract\xE8re du \verb|<token>|.
+
+Si un token test\xE9 par \verb|\if| est une s\xE9quence de contr\xF4le, son code de caract\xE8re est vu \xE9gal \xE0 256.
+\end{regle}
+
+\showcode/1) \def\foo{xxy}\def\bar{aab}
+   \if\foo\bar vrai\else faux\fi\qquad
+2) \if aA vrai\else faux\fi\qquad% "a" et "A" n'ont pas les m\xEAmes charcode
+3) \if\relax\noexpand\foo vrai\else faux\fi\qquad% \relax et \foo ont un charcode=256\xA4\idx*\noexpand\xA4
+4) \let\foo=&\if\foo &vrai\else faux\fi\qquad% \foo est vue comme "&"
+5) \if\string~\noexpand~vrai\else faux\fi\xA4\idx*\string\cidx*\~\xA4/
+
+\begin{exercice}\label{ifcs.la.vraie}
+Utiliser le test \verb|\if| pour que la macro \xA7\ifcs[|(]\verb|<token>{<vrai>}{<faux>}| vue pr\xE9c\xE9demment ne renvoie \verb|<vrai>| que si le \verb|<token>| est une s\xE9quence de contr\xF4le, c'est-\xE0-dire lorsqu'il commence par le caract\xE8re d'\xE9chappement.
+\solution
+Il est in\xE9vitable que nous allons devoir tester le caract\xE8re d'\xE9chappement. Pour cela, nous allons ouvrir un groupe semi-simple et imposer un caract\xE8re d'\xE9chappement avec \idx\escapechar. Nous le prendrons \xE9gal \xE0 \xAB\verb|@|\xBB mais tout autre choix conviendrait; l'essentiel est de se pr\xE9munir d'un r\xE9gime sp\xE9cial o\xF9 l'\idx\escapechar serait n\xE9gatif ou nul. Il suffit ensuite de tester si les deux caract\xE8res qui se trouvent au d\xE9but de \xAB\idx\string\verb|#1a|\xBB (le \xAB\verb|a|\xBB prot\xE8ge d'un argument vide) et \xAB\idx\string\idx\relax\xBB sont les m\xEAmes. Apr\xE8s avoir ferm\xE9 le groupe, les classiques \xA7\firstoftwo ou \xA7\secondoftwo renvoient \verb|<vrai>| ou \verb|<faux>|. Pour isoler le premier caract\xE8re d'une chaine arbitraire, la macro \xA7\firstto at nil sera utilis\xE9e.
+
+\showcode/\catcode`\@11
+\def\ifcs#1{%\xA4\xA7*\ifcs\xA4
+	\begingroup\xA4\idx*\begingroup\xA4
+		\escapechar=`\@ % prend "@" comme caract\xE8re d'\xE9chappement\xA4\idx*\escapechar\xA4
+		\if% les premiers caract\xE8res de
+			\expandafter\firstto at nil\string#1a\@nil% "#1a"\xA4\xA7*\firstto at nil\idx*\string\xA4
+			\expandafter\firstto at nil\string\relax\@nil% et "\relax" sont-ils \xE9gaux ?\xA4\idx*\string\xA7*\firstto at nil\xA4
+			\endgroup\expandafter\firstoftwo% si oui, fermer le groupe et renvoyer "vrai"\xA4\xA7*\firstoftwo\idx*\endgroup\xA4
+		\else% sinon, fermer le groupe et renvoyer "faux"
+			\endgroup\expandafter\secondoftwo\xA4\xA7*\secondoftwo\xA4
+		\fi
+}
+\catcode`\@12
+1) \def\foo{bar}\ifcs\foo{vrai}{faux}\qquad
+2) \ifcs\def{vrai}{faux}\qquad
+3) \ifcs A{vrai}{faux}\qquad
+\catcode`\*=13 
+4) \let*=W \ifcs*{vrai}{faux}\qquad
+5) \let*=\relax \ifcs*{vrai}{faux}\qquad
+6) \let\foo=A \ifcs\foo{vrai}{faux}\qquad
+7) \ifcs\bgroup{vrai}{faux}\xA4\idx*\bgroup\xA4/
+\xA7*\ifcs[|)]\end{exercice}\tidx*[|)]{if}
+
+\subsection{Test incomplets}\idx*[|(]{test incomplet}
+Entrons \xE0 pr\xE9sent au plus profond de la m\xE9canique \TeX ienne des tests et examinons les tests incomplets. Un test est dit incomplet lorsque les choses \xE0 comparer sont en nombre insuffisant et font intervenir les primitives du test lui-m\xEAme, \xE0 savoir \tidx[|etc]{else} et \tidx[|etc]{fi}.
+\grandsaut
+
+Demandons-nous quelle est la comparaison faite dans ce test :
+
+\centrecode-\ifx a\fi-
+
+\noindent Si l'on s'en tient \xE0 la d\xE9finition de \tidx{ifx}, le \xAB\verb|a|\xBB est compar\xE9 au \verb|\fi| mais ce m\xEAme \verb|\fi|, captur\xE9 par la comparaison et d\xE8s lors indisponible, ne casse-t-il pas l'\xE9quilibrage entre le \tidx{ifx} et le \verb|\fi| ?
+
+Dans le m\xEAme ordre d'id\xE9e, que se passe-t-il lors de ce test ?
+
+\centrecode-\ifnum1=2\else3\fi 4-
+
+\noindent Lorsque le \verb|2| est lu, \TeX{} est en train de lire un nombre et se trouve donc en phase de \idx{d\xE9veloppement maximal}. Va-t-il d\xE9velopper le \verb|\else|, puis lire \verb|3| puis poursuivre son d\xE9veloppement et manger le \verb|\fi|? Ensuite, continue-t-il son d\xE9veloppement plus loin avec le 4 et avec ce qui se trouve apr\xE8s ? Le \verb|\else| et le \verb|\fi|, mang\xE9s par la lecture du nombre, rompent-ils l'\xE9quilibrage entre le \tidx{ifnum} et le \verb|\fi| ?
+
+\idx*[!sp\xE9cial|(]{\relax}\begin{regle}
+\relax Lorsqu'un \verb|\else| ou un \verb|\fi| appari\xE9 avec un test est rencontr\xE9 lors de l'\xE9valuation de ce test, \TeX{} ins\xE8re un \verb|\relax| sp\xE9cial afin que le \verb|\else| ou le \verb|\fi| demeurent hors de l'\xE9valuation faite par le test.
+\end{regle}
+
+Ainsi, le test \xAB\verb|\ifx a\fi|\xBB devient \xAB\verb|\ifx a|\boxtoken\relax\verb|\fi|\xBB o\xF9 le \boxtoken\relax est un \idx\relax sp\xE9cial ins\xE9r\xE9 par \TeX{} et qui sera compar\xE9 avec \xAB\verb|a|\xBB. De m\xEAme, le test \xAB\verb|\ifnum1=2\else3\fi|\xBB devient \xAB\verb|\ifnum1=2|\boxtoken\relax\verb|\else3\fi|\xBB o\xF9 le \idx\relax sp\xE9cial interrompt la lecture du nombre 2.
+\grandsaut
+
+Voici comment d\xE9finir une macro \xA7\specialrelax dont le texte de remplacement est un \idx\relax sp\xE9cial :
+
+\centrecode-\edef\specialrelax{\ifnum1=1\fi}-
+
+\noindent Ici, un \boxtoken\relax sera ins\xE9r\xE9 avant le \verb|\fi| et comme le test est vrai, ce \boxtoken\relax sera tout ce qui reste dans la branche du test.
+
+\showcode/\edef\specialrelax{\ifnum1=1\fi}\xA4\xA7*\specialrelax\xA4
+\meaning\specialrelax\xA4\idx*\meaning\xA4/
+
+Pourquoi dit-on \idx\relax \emph{sp\xE9cial} et non pas \idx\relax tout court ? Les \idx\relax sp\xE9ciaux ins\xE9r\xE9s par \TeX{} sont diff\xE9rents des \idx\relax ordinaires lus dans le code source aux yeux de \TeX{} lui-m\xEAme. En voici la preuve :
+
+\showcode/\edef\specialrelax{\ifnum1=1\fi}% texte de remplacement = \relax sp\xE9cial\xA4\xA7*\specialrelax\xA4
+\edef\normalrelax{\relax}% texte de remplacement = \relax normal
+\meaning\specialrelax\par\xA4\idx*\meaning\xA4
+\meaning\normalrelax\par
+Les 2 \string\relax{} sont \ifx\specialrelax\normalrelax identiques\else diff\xE9rents\fi.\xA4\idx*\string\xA7*\specialrelax\xA4/
+
+ Ils sont diff\xE9rents car \boxtoken\relax n'est \emph{pas} une primitive. C'est un token interne d\xE9fini dans le programme \texttt{tex} lui-m\xEAme qui se donne l'apparence de \idx\relax mais qui est cod\xE9 en dur et qui n'est pas modifiable par l'utilisateur. Autant on pourrait vivre dangereusement et red\xE9finir la primitive \idx\relax, autant il est impossible de red\xE9finir \boxtoken\relax :
+
+\errcode/\edef\specialrelax{\ifnum1=1\fi}\xA4\xA7*\specialrelax\xA4
+\expandafter\def\specialrelax{foobar}% red\xE9finition un \relax sp\xE9cial\xA4\xA7*\specialrelax\xA4/{Missing control sequence inserted}%
+\idx*[!sp\xE9cial|)]\relax\idx*[|)]{test incomplet}
+
+\section{Tests successifs}
+\subsection{Programmation du test \texttt{\textbackslash ifnumcase}}\xA7*\ifnumcase[|(]%
+Nous avons vu le test \tidx{ifcase}\verb|<nombre>|, cousin de \tidx{ifnum}, qui permettait de d\xE9cider que faire selon des valeurs enti\xE8res du \verb|<nombre>|. L'inconv\xE9nient est que ces valeurs doivent commencer \xE0 0 et se suivre de 1 en 1. Cette contrainte rend ce test inutilisable si l'on souhaite tester si le \verb|<nombre>| est successivement \xE9gal \xE0 des valeurs non cons\xE9cutives et distantes les unes des autres. L'id\xE9e est donc de cr\xE9er un test qui d\xE9cide que faire selon des valeurs enti\xE8res pr\xE9cis\xE9es par l'utilisateur (par exemple $-5$, 14, $-16$, 20) et offrir une branche facultative \xA7\elseif o\xF9 un code alternatif sera ex\xE9cut\xE9 si aucune \xE9galit\xE9 n'a \xE9t\xE9 rencontr\xE9e.
+
+Nous allons nous fixer la syntaxe suivante :
+
+\centrecode/\ifnumcase{<nombre>}%
+	{<valeur 1>}{<code 1>}
+	{<valeur 2>}{<code 2>}
+	...
+	{<valeur n>}{<code n>}
+\elseif
+	<code alternatif>
+\endif\xA4\xA7*\endif\xA4/
+
+Le \xA7\elseif et le \verb|<code alternatif>| qui le suit sont facultatifs.
+
+De plus, nous allons nous imposer une contrainte : lorsqu'un \verb|<code>| est ex\xE9cut\xE9, il doit pouvoir acc\xE9der aux tokens qui suivent le \xA7\endif. Autrement dit, ce \verb|<code>| doit \xEAtre ex\xE9cut\xE9 \xE0 la toute fin du traitement, juste avant que la macro ne rende la main.
+
+L'id\xE9e directrice est de lire tout d'abord le \verb|<nombre>| puis de passer la main \xE0 une macro r\xE9cursive qui va lire ensuite \emph{un seul} argument. Si cet argument est :
+
+\begin{itemize}
+	\item une \verb|<valeur k>|, lire le \verb|<code k>| et l'ex\xE9cuter si le test est vrai apr\xE8s avoir tout mang\xE9 jusqu'au \xA7\endif. S'il est faux, recommencer;
+	\item \xA7\elseif, aucun test n'a \xE9t\xE9 vrai et il faut ex\xE9cuter le \verb|<code alternatif>| apr\xE8s avoir tout mang\xE9 jusqu'au \xA7\endif;
+	\item \xA7\endif, cela signifie la fin du processus et correspond au cas o\xF9 \xA7\elseif n'est pas pr\xE9sent et aucun test n'a \xE9t\xE9 vrai.
+\end{itemize}
+
+Comme nous ne savons pas encore tester si un argument est une \verb|<valeur>| (c'est-\xE0-dire un entier), nous allons d'abord tester si l'argument est \xA7\elseif puis s'il est \xA7\endif et si les deux tests pr\xE9c\xE9dents sont n\xE9gatifs, nous consid\xE8rerons que c'est un entier.
+
+Afin d'\xEAtre propre dans la programmation, l'ensemble du processus se d\xE9roulera dans un groupe semi-simple. Il conviendra de le fermer au bon moment. Pour faciliter la comparaison avec \tidx{ifx}, les macros \xA7\elseif et \xA7\endif seront des \idx[|(]{quark}s locaux \xE0 ce groupe.
+
+\begin{algo}
+	\item ouvrir un groupe, lire le \verb|<nombre>|, d\xE9finir les quarks \verb|\elseif| et \verb|\endif|;
+	\item lire le premier argument $x$ qui suit ;
+	\begin{algo}
+		\item si $x={}$\xA7\elseif, fermer le groupe et ex\xE9cuter tout ce qui reste jusqu'\xE0 \xA7\endif ;
+		\item sinon
+		\begin{itemize}
+			\item si $x={}$\xA7\endif fermer le groupe;
+			\item sinon, cela signifie que $x$ est une \verb|<valeur>|
+			\begin{algo}%[label=(\roman*)]
+				\item si $x={}$\verb-<nombre>-, fermer le groupe, ex\xE9cuter l'argument suivant apr\xE8s voir tout supprim\xE9 tout jusqu'\xE0 \xA7\endif ;
+				\item si $x\neq{}$\verb-<nombre>-, manger l'argument suivant et retourner en 2.
+			\end{algo}
+		\end{itemize}
+	\end{algo}
+\end{algo}
+
+Nous aurons besoin d'une macro auxiliaire r\xE9cursive pour le point 2 ainsi que d'une macro auxiliaire qui s'occupe du point 2a que nous appellerons \verb|\idto at endif| :
+
+\centrecode-\def\idto at endif#1\endif{#1}-\xA7*\endif
+
+\noindent et d'une autre pour le point 2bi) que nous appellerons \verb|\firstto at endif|. Elle sera charg\xE9e de lire l'argument suivant (argument non d\xE9limit\xE9 \verb|#1|) et de lire tout ce qui se trouve jusqu'au \xA7\endif (qui sera un argument d\xE9limit\xE9). Son texte de remplacement sera le premier argument :
+
+\centrecode-\def\firstto at endif#1#2\endif{#1}-\xA7*\endif
+
+Voici le code :
+
+\showcode/\catcode`\@11
+\def\ifnumcase#1{%\xA4\xA7*\ifnumcase\xA4
+	\begingroup\xA4\idx*\begingroup\xA4
+	\def\elseif{\elseif}\def\endif{\endif}% d\xE9finir deux "quarks" locaux\xA4\xA7*\elseif\xA7*\endif\xA4
+	\def\nombre@{#1}% stocker le nombre \xE0 comparer dans \nombre@
+	\ifnumcase at i% appeller la macro r\xE9cursive
+}
+
+\def\ifnumcase at i#1{%
+	\def\nxt at arg{#1}% stocker l'argument suivant
+	\ifx\nxt at arg\elseif% si c'est \elseif\xA4\xA7*\elseif\xA4
+		\def\next at todo{\endgroup\idto at endif}% fermer le groupe et aller \xE0 \idto at endif
+	\else
+		\ifx\nxt at arg\endif% si c'est \endif\xA4\xA7*\endif\xA4
+			\let\next at todo\endgroup% fermer le groupe
+		\else
+			\ifnum\nombre@=\nxt at arg% s'il y a \xE9galit\xE9
+				\def\next at todo{\endgroup\firstto at endif}% fermer le groupe puis \firstto at endif
+			\else% sinon
+				\let\next at todo=\ifnumcase at ii% aller \xE0 \ifnumcase at ii
+			\fi
+		\fi
+	\fi
+	\next at todo% ex\xE9cuter l'action d\xE9cid\xE9e ci-dessus
+}
+
+\def\ifnumcase at ii#1{\ifnumcase at i}
+\def\idto at endif#1\endif{#1}
+\def\firstto at endif#1#2\endif{#1}
+\catcode`\@12
+\def\swaptwo#1#2{#2#1}\xA4\xA7*\swaptwo\xA4
+\def\testenombre#1{%
+	\ifnumcase{#1}
+		{1}{C'est "un" et je prends le premier argument: \firstoftwo}\xA4\xA7*\firstoftwo\xA4
+		{3}{J'ai vu un "trois" et je mange les deux arguments : \gobtwo}\xA4\xA7*\gobtwo\xA4
+		{15}{L'argument est "15" et je prends le second argument : \secondoftwo}\xA4\xA7*\secondoftwo\xA4
+	\elseif\xA4\xA7*\elseif\xA4
+		ni 1, ni 3, ni 5 et j'inverse les deux arguments : \swaptwo\xA4\xA7*\swaptwo\xA4
+	\endif\xA4\xA7*\endif\xA4
+}
+\testenombre{3}{foo}{bar}\par
+\testenombre{16}{foo}{bar}\par
+\testenombre{15}{foo}{bar}\par
+\testenombre{1}{foo}{bar}/
+
+Pour mettre en \xE9vidence que chaque \verb|<code>| a acc\xE8s \xE0 ce qui se trouve imm\xE9diatement apr\xE8s le \xA7\endif, les macros \xA7\firstoftwo, \xA7\secondoftwo sont appel\xE9es \xE0 la fin des \verb|<code>| pour qu'elles agissent sur les arguments qui suivent le \xA7\endif. Une nouvelle macro \xA7\swaptwo qui inverse l'ordre des deux arguments suivants est \xE9galement utilis\xE9e.
+
+\begin{exercice}
+En l'\xE9tat, la macro \xA7\ifnumcase n'est pas purement d\xE9veloppable, c'est-\xE0-dire qu'on ne peut pas la mettre dans un \idx\edef. Comment pourrait-on la modifier pour qu'elle le devienne (\xE0 condition bien s\xFBr que les \verb|<code>| le soient) ?
+\solution
+Les primitives non d\xE9veloppables doivent \xEAtre supprim\xE9es : \idx\begingroup, \idx\endgroup, \idx\def et \idx\let. Il n'y aura plus de groupe semi-simple et les \idx{quark}s seront donc d\xE9finis de fa\xE7on globale, \xE0 l'ext\xE9rieur de la macro \xA7\ifnumcase.
+
+Dans les branches des tests de \verb|\ifnumcase at i|, nous pouvons facilement nous passer de la macro \verb|\next at todo| \xE0 condition de recourir aux macros \xA7\firstoftwo et \xA7\secondoftwo qui rejettent hors des branches les codes ex\xE9cut\xE9s selon l'issue du test. En revanche, il est plus difficile de se passer de \verb|\nombre@| qui a stock\xE9 le \verb|<nombre>| dans la macro chapeau. La seule alternative est de passer le \verb|<nombre>| comme argument suppl\xE9mentaire \xE0 la macro r\xE9cursive.
+
+Le code tend \xE0 se simplifier : l'essentiel est d\xE9sormais fait par la macro r\xE9cursive \xA7\ifnumcase qui \xE0 chaque fois, va lire le m\xEAme premier argument (le \verb|<nombre>|) ainsi qu'un second argument qui devra \xEAtre test\xE9 pour d\xE9cider que faire. Dans le cas o\xF9 ce second argument est une \verb|<valeur>|, il faudra aller lire le \verb|<code>| correspondant, soit pour l'ex\xE9cuter, soit pour le manger avant de repartir pour un tour.
+
+\showcode/\catcode`\@11
+\def\endif{\endif}\def\elseif{\elseif}% d\xE9finit les quarks\xA4\xA7*\elseif\xA7*\endif\xA4
+
+\def\ifnumcase#1#2{% #1=<nombre>   #2=prochain argument
+	\ifx\elseif#2% si #2 est \elseif\xA4\xA7*\elseif\xA4
+	\expandafter\firstoftwo\else\expandafter\secondoftwo\fi\xA4\xA7*\firstoftwo\xA7*\secondoftwo\xA4
+		\idto at endif% aller \xE0 \idto at endif, sinon :
+		{\ifx\endif#2% si #2 est \endif\xA4\xA7*\endif\xA4
+		\expandafter\firstoftwo\else\expandafter\secondoftwo\fi\xA4\xA7*\secondoftwo\xA4
+			{}% ne rien faire. Sinon #2 est une <valeur i>:
+			{\ifnum#1=#2 % s'il y a \xE9galit\xE9 entre <nombre> et <valeur i>
+			\expandafter\firstoftwo\else\expandafter\secondoftwo\fi\xA4\xA7*\secondoftwo\xA4
+				\firstto at endif% aller \xE0 \firstto at endif
+				{\ifnumcase at i{#1}}% sinon aller \xE0 \ifnumcase at i
+			}%
+		}%
+}
+
+\def\ifnumcase at i#1#2{% #1=<nombre>  #2=<code i> \xE0 suivre qui est mang\xE9
+	\ifnumcase{#1}% retourner \xE0 \ifnumcase en transmettant #1
+}
+
+\def\idto at endif#1\endif{#1}
+\def\firstto at endif#1#2\endif{#1}
+\catcode`\@12
+\def\swaptwo#1#2{#2#1}\xA4\xA7*\swaptwo\xA4
+\def\testenombre#1{%
+	\ifnumcase{#1}
+		{1}{C'est "un" et je prends le premier argument: \firstoftwo}\xA4\xA7*\firstoftwo\xA4
+		{3}{J'ai vu un "trois" et je mange les deux arguments : \gobtwo}\xA4\xA7*\gobtwo\xA4
+		{15}{L'argument est "15" et je prends le second argument : \secondoftwo}\xA4\xA7*\secondoftwo\xA4
+	\elseif\xA4\xA7*\elseif\xA4
+		ni 1, ni 3, ni 5 et j'inverse les deux arguments : \swaptwo\xA4\xA7*\swaptwo\xA4
+	\endif\xA4\xA7*\endif\xA4
+}
+\testenombre{3}{foo}{bar}\par
+\testenombre{16}{foo}{bar}\par
+\testenombre{15}{foo}{bar}\par
+\edef\macro{\testenombre{1}{foo}{bar}}\meaning\macro/
+\idx*[|)]{quark}\xA7*\ifnumcase[|)]\end{exercice}
+
+\subsection{Programmation du test \texttt{\textbackslash ifxcase}}\xA7*\ifxcase[|(]%
+Il ne nous reste plus qu'\xE0 faire la m\xEAme chose avec le test \tidx{ifx} en programmant une macro \verb|\ifxcase| dont voici la syntaxe :
+
+\centrecode/\ifxcase <token>
+	<token 1>{<code 1>}
+	<token 2>{<code 2>}
+	...
+	<token n>{<code n>}
+\elseif%\xA4\xA7*\elseif\xA4
+	<code alternatif>
+\endif\xA4\xA7*\endif\xA4/
+
+\noindent qui compare successivement \verb|<token>| avec \verb|<token 1>|, \verb|<token 2>|, etc, o\xF9 les comparaisons sont faites au sens de \tidx{ifx}. Si un des tests est positif, le \verb|<code i>| correspondant sera ex\xE9cut\xE9 et sinon, ce qui se trouve apr\xE8s la macro facultative \xA7\elseif le sera.
+
+Il n'y a rien de bien difficile, il suffit de recopier le code de \xA7\ifnumcase en rempla\xE7ant le test \tidx{ifnum} par \tidx{ifx}: \label{ifxcase}
+
+\showcode/\catcode`\@11
+\def\endif{\endif}\def\elseif{\elseif}%\xA4\xA7*\elseif\xA7*\endif\xA4
+\def\ifxcase#1#2{% #1=<token>   #2=prochain argument
+	\ifx\elseif#2% si #2 est \elseif\xA4\xA7*\elseif\xA4
+	\expandafter\firstoftwo\else\expandafter\secondoftwo\fi\xA4\xA7*\firstoftwo\xA7*\secondoftwo\xA4
+		\idto at endif% aller \xE0 \idto at endif, sinon :
+		{\ifx\endif#2% si #2 est \endif\xA4\xA7*\endif\xA4
+		\expandafter\firstoftwo\else\expandafter\secondoftwo\fi\xA4\xA7*\secondoftwo\xA4
+			{}% ne rien faire. Sinon #2 est un <token i>:
+			{\ifx#1#2% s'il y a \xE9galit\xE9 entre <token> et <token i>
+			\expandafter\firstoftwo\else\expandafter\secondoftwo\fi\xA4\xA7*\secondoftwo\xA4
+				\firstto at endif% aller \xE0 \firstto at endif
+				{\ifxcase at i{#1}}% sinon aller \xE0 \ifnumcase at i
+			}%
+		}%
+}
+\def\ifxcase at i#1#2{% #1=<token>  #2=<code i> \xE0 suivre (qui est mang\xE9)
+	\ifxcase{#1}% retourner \xE0 \ifxcase en transmettant #1
+}
+\def\idto at endif#1\endif{#1}
+\def\firstto at endif#1#2\endif{#1}
+\catcode`\@12
+\def\testtoken#1{%\xA4\xA7*\testtoken\xA4
+	\ifxcase{#1}
+		a{Le token est "a"}
+		+{J'ai vu un "+"}
+		\relax{L'argument est "\string\relax"}\xA4\idx*\string\xA4
+	\elseif\xA4\xA7*\elseif\xA4
+		Tous les tests sont n\xE9gatifs%
+	\endif\xA4\xA7*\endif\xA4
+}
+1) \testtoken a\par
+2) \let\foo=a\testtoken\foo\par
+3) \testtoken+\par
+4) \testtoken\relax\par
+5) \edef\foo{\testtoken\relax}\meaning\foo\par\xA4\idx*[|etc]\meaning\forbidindex\meaning\xA4
+6) \edef\foo{\testtoken W}\meaning\foo\xA4\xA7*\testtoken\xA4/
+
+On constate aux cas \nos1 et 2 que le test est positif aussi bien lorsque le \verb|<token>| est un \xAB\verb|a|\xBB explicite que lorsqu'il est une macro \idx\let-\xE9gale au caract\xE8re \xAB\verb|a|\xBB.\xA7*\ifxcase[|)]%
+
+\chapter{Une boucle \xAB loop repeat \xBB}
+\section{Impl\xE9mentation de plain-\TeX}
+Plain-\TeX{} d\xE9finit lui-m\xEAme sa boucle \xAB \idx\loop\ldots\idx\repeat \xBB dont voici l'impl\xE9mentation telle qu'elle a \xE9t\xE9 \xE9crite par \idx*{Knuth Donald}D.~\textsc{Knuth} :
+
+\centrecode-\def\loop#1\repeat{\def\body{#1}\iterate}\xA4\idx*\iterate\idx*\loop\xA4
+\def\iterate{\body \let\next\iterate \else\let\next\relax\fi \next}
+\let\repeat=\fi-
+
+Il est clair que la macro \idx\loop est \xE0 argument d\xE9limit\xE9 (le d\xE9limiteur est \idx\repeat) et stocke dans la macro \idx\body tout ce qui se trouve entre \idx\loop et \idx\repeat (que l'on appelle \xAB corps de la boucle\xBB) avant d'appeler la macro \idx\iterate. On remarque \xE9galement qu'aucune macro n'est d\xE9clar\xE9e \idx\long et donc il faudra proscrire la primitive \idx[|etc]\par\forbidindex\par{} entre \idx\loop et \idx\repeat. Ensuite, l'id\xE9e est que ce qui se trouve entre \idx\loop et \idx\repeat, stock\xE9 dans \idx\body, \emph{doit} contenir un test. Ce test, s'il est positif, autorisera la boucle ex\xE9cuter une it\xE9ration de plus tandis que s'il est n\xE9gatif, il constitue la \emph{condition d'arr\xEAt} de la boucle qui lui commande de s'arr\xEAter. Cela suppose que le corps de la boucle modifie un param\xE8tre pris en compte par le test afin que ce dernier devienne \xE0 un moment n\xE9gatif pour permettre la sortie de la boucle et \xE9viter ainsi une boucle infinie.
+
+Le m\xE9canisme est assez facile \xE0 saisir : ce test sera ex\xE9cut\xE9 lorsque \idx\iterate puis \idx\body seront d\xE9velopp\xE9s. Si ce test est positif, \verb|\next| est rendue \idx\let-\xE9gale \xE0 \idx\iterate et sinon, elle est rendue \idx\let-\xE9gale \xE0 \idx[|etc]\relax\forbidindex\relax. Cette macro \verb|\next| est ensuite appel\xE9e apr\xE8s \xEAtre sorti du test, ce qui rend la r\xE9cursivit\xE9 terminale\idx*{r\xE9cursivit\xE9!terminale}.
+
+La structure de la boucle est donc la suivante :
+
+\centrecode-\loop
+	<code a>
+	<test>
+	<code b>
+\repeat-
+
+\noindent o\xF9 les \verb|<code a>| et \verb|<code b>| sont facultatifs, c'est-\xE0-dire que l'un ou l'autre peuvent \xEAtre r\xE9duit \xE0 0 token. Il est en revanche important de comprendre que \verb|<code a>| est toujours ex\xE9cut\xE9 au moins une fois puisqu'il vient avant le test.
+
+De par sa construction, il est \xE9galement important de remarquer que ce qui se trouve entre \idx\loop et \idx\repeat ne doit pas contenir un test accompagn\xE9 d'un \verb|\else| puisqu'un \verb|\else| est d\xE9j\xE0 \xE9crit en dur dans la macro \idx\iterate. Si l'utilisateur \xE9crivait un \verb|\else| par m\xE9garde, cela provoquerait une erreur de type \xAB\verb|extra \else|\xBB lorsque \TeX{} atteindrait le second \verb|\else|. Malgr\xE9 cette petite contrainte, cette structure est tr\xE8s souple du fait que le test peut se trouver o\xF9 l'on veut entre \idx\loop et \idx\repeat.
+
+Enfin, on constate \xE0 la derni\xE8re ligne que \idx\repeat est rendu \idx\let-\xE9gal \xE0 \verb|\fi| ce qui a pour cons\xE9quence que \idx\repeat sera vu par \TeX{} comme un \verb|\fi| et donc pris en compte lors du comptage interne de \TeX{} des tests, \verb|\else| et des \verb|\fi|. En d'autres termes, le \idx\repeat sera bien appari\xE9 avec le \verb|<test>| se trouvant entre \idx\loop et \idx\repeat et par cons\xE9quent, la boucle peut \xEAtre mise dans les branches d'un test sans provoquer de mauvais appariements entre les tests et les \verb|\fi|. Une structure de ce type est donc tout \xE0 fait envisageable :
+
+\centrecode-<test>
+	<code 1>
+	\loop
+		...
+	\repeat
+	<code 2>
+\else
+	<code 3>
+	\loop
+		...
+	\repeat
+	<code 4>
+\fi-
+
+Voici \xE0 titre d'exemple comment on peut programmer la macro \xA7\compte vue dans un exercice du chapitre~\ref{compte} :
+
+\showcode/\newcount\xx % d\xE9finit un compteur utilis\xE9 dans la boucle\xA4\idx*\newcount\xA4
+\def\compte#1{%\xA4\xA7*\compte\xA4
+	\xx=0 % initialise le compteur
+	\loop% d\xE9but de la boucle\xA4\idx*\loop\xA4
+		\advance\xx1 % incr\xE9mente le compteur\xA4\idx*\advance\xA4
+		\ifnum\xx<#1 % s'il est inf\xE9rieur \xE0 la borne
+		  \number\xx , % affiche le nombre et la virgule\xA4\idx*[|etc]\number\forbidindex\number\xA4
+	\repeat% et recommence\xA4\idx*\repeat\xA4
+	\ifnum#1>0 \number\xx\relax\fi% si le nombre #1 est >0, afficher le dernier nombre
+	}
+a) \compte{1}.\qquad b) \compte{-3}.\qquad c) \compte{7}.\xA4\xA7*\compte\xA4/
+
+\section{Impl\xE9mentation de \LaTeX}
+Le \idx[!\LaTeX]{format}\LaTeX{} red\xE9finit la boucle \idx\loop\ldots\idx\repeat de cette fa\xE7on :
+
+\centrecode-\long\def\loop#1\repeat{%\xA4\idx*\long\idx*\loop\idx*\repeat\xA4
+  \def\iterate{#1\relax\expandafter\iterate\fi}%\xA4\idx*\iterate\xA4
+  \iterate
+  \let\iterate\relax}\xA4\idx*\iterate\xA4
+\let\repeat=\fi-
+
+La macro \idx\loop est d\xE9clar\xE9e \idx\long et l'on fait l'\xE9conomie de la macro \idx\body en d\xE9clarant \idx\iterate comme une \xAB sous-macro \xBB de \idx\loop de telle sorte que l'argument \verb|#1| lui soit accessible. En consid\xE9rant que \verb|#1| contient un test, on voit clairement que ce test peut \xEAtre accompagn\xE9 d'un \verb|\else| puisque le code de la macro \idx\iterate ne comporte pas cette primitive mais seulement un \verb|\fi|. Le plus simple est de faire fonctionner la boucle dans les cas o\xF9 son corps contient un \verb|\else| ou pas :\medbreak
+
+\noindent
+\begin{minipage}[t]{.5\linewidth}
+\footnotesize
+\hfill Sans \verb|\else|\hfill\null
+\centrecode-\loop
+	<code a>
+	<test>
+		<code b>
+\repeat-
+\end{minipage}%
+\begin{minipage}[t]{.5\linewidth}
+\footnotesize
+\hfill Avec \verb|\else|\hfill\null
+\centrecode-\loop
+	<code a>
+	<test>
+		<code b>
+	\else
+		<code c>
+\repeat-
+\end{minipage}\medbreak
+
+Voil\xE0 ce qui est stock\xE9 dans la macro \idx\iterate dans chaque cas :\medbreak
+
+\noindent
+\begin{minipage}[t]{.5\linewidth}
+\footnotesize
+\hfill Sans \verb|\else|\hfill\null
+\centrecode-<code a>
+<test>
+	<code b>\relax
+	\expandafter\iterate
+\fi-
+\end{minipage}%
+\begin{minipage}[t]{.5\linewidth}
+\footnotesize
+\hfill Avec \verb|\else|\hfill\null
+\centrecode-<code a>
+<test>
+	<code b>
+\else
+	<code c>\relax
+	\expandafter\iterate
+\fi-
+\end{minipage}\medbreak
+
+Il est maintenant facile de constater que si le corps de la boucle contient un \verb|\else|, c'est la branche du test n\xE9gatif (apr\xE8s le \verb|\else|) qui maintiendra la r\xE9cursivit\xE9. En revanche, s'il n'y a pas de \verb|\else|, c'est la branche du test positif qui la maintient. Autrement dit, la condition d'arr\xEAt est un test \emph{n\xE9gatif} s'il n'y a pas de \verb|\else| alors que c'est un test \emph{positif} s'il y en a.
+
+Malgr\xE9 ce petit manque de coh\xE9rence, on peut dire que l'impl\xE9mentation \LaTeX{} est sup\xE9rieure \xE0 celle de plain-\TeX{} puisque la souplesse de pouvoir mettre de \verb|\else| dans la boucle rend parfois service, sans compter que l'on peut \xE9galement faire appel \xE0 \tidx{unless} pour \xE9changer les branches du test.
+
+\section{Imbrications de boucles}
+Malgr\xE9 leur c\xF4t\xE9 pratique, ni l'impl\xE9mentation \TeX{} ni celle de \LaTeX{} ne permettent l'imbrication de boucles \idx\loop\ldots\idx\repeat, principalement \xE0 cause de deux choses :
+
+\begin{itemize}
+	\item si deux boucles \xE9taient imbriqu\xE9es, le \idx\repeat de la boucle int\xE9rieure serait pris comme fin de la boucle ext\xE9rieure puisqu'avec les arguments d\xE9limit\xE9s, la premi\xE8re occurrence du d\xE9limiteur est prise en compte ;
+	\item la macro \idx\iterate serait red\xE9finie par la boucle int\xE9rieure.
+\end{itemize}
+
+Avec la syntaxe actuelle, aucune impl\xE9mentation facile \xE0 programmer et n'utilisant pas de groupe permet d'imbriquer des boucles \idx\loop \idx\repeat n'est faisable. La difficult\xE9 est de trouver ce qui se trouve entre un \idx\loop et son \idx\repeat appari\xE9 ! Nous allons donc tenter de b\xE2tir une boucle \xA7\xloop\verb|...|\xA7\xrepeat, fonctionnant de la m\xEAme fa\xE7on que \verb|\loop...\repeat| sauf que l'imbrication des boucles sera possible.
+
+Pour commencer, nous allons nous attacher \xE0 collecter le code compris entre un \xA7\xloop et son \xA7\xrepeat appari\xE9. Ce code sera stock\xE9 dans la macro \verb|\xiterate| et simplement \emph{affich\xE9}  :
+
+\begin{algo}
+	\item d\xE9finir un compteur \verb|\cnt at repeat| qui comptabilisera les occurrences de \xA7\xrepeat rencontr\xE9es, et l'initialiser \xE0 0. Initialiser \verb|\xiterate| \xE0 vide;
+	\item ajouter \xE0 \verb|\xiterate| tout le code qui se trouve jusqu'au prochain \xA7\xrepeat;
+	\item stocker dans \verb|\cnt at loop| le nombre de fois que \xA7\xloop est contenu dans le texte de remplacement de \verb|\xiterate|;
+	\item tester si \verb|\cnt at loop|${}={}$\verb|\cnt at repeat|;
+	\begin{algo}
+		\item si le test est positif, afficher le texte de remplacement de \verb|\xiterate| \xE0 l'aide \idx\detokenize;
+		\item sinon, incr\xE9menter \verb|\cnt at repeat|, ajouter \xA7\xrepeat \xE0 \verb|\xiterate| et retourner en 2.
+	\end{algo}
+\end{algo}
+
+Voici un code \TeX{} qui transcrit cet algorithme, o\xF9 nous nous servons des macros \xA7\addtomacro et \xA7\ifin vues pr\xE9c\xE9demment. Nous utiliserons aussi la macro \verb|\cnttimestocs| vue dans la solution \xE0 la page~\pageref{cnttimes} :
+
+\showcode/\catcode`\@11
+\newcount\cnt at repeat % d\xE9finit le compteur de \xrepeat\xA4\idx*\newcount\xA4
+
+\def\xloop{%\xA4\xA7*\xloop\xA4
+	\def\xiterate{}% initialiser \xiterate \xE0 vide
+	\cnt at repeat\z@% initialiser le compteur de \xrepeat\xA4\idx*\z@\xA4
+	\xloop at i% aller \xE0 la macro r\xE9cursive
+}
+
+\long\def\xloop at i#1\xrepeat{%\xA4\idx*\long \xA7*\xrepeat\xA4
+	\addtomacro\xiterate{#1}% ajoute ce qui est avant le premier \xrepeat\xA4\xA7*\addtomacro\xA4
+	\exparg\cnttimestocs{\xiterate}\xloop\cnt at loop
+	% combien de \xloop dans \xiterate\xA4\xA7*\cnttimestocs\xA4
+	\ifnum\cnt at loop=\cnt at repeat\relax
+		\expandafter\firstoftwo\else\expandafter\secondoftwo\xA4\xA7*\firstoftwo\xA7*\secondoftwo\xA4
+	\fi
+		{% autant que de \xrepeat -> \detokenize pour afficher
+		"\detokenize\expandafter{\xiterate}"%
+		}
+		{\addtomacro\xiterate\xrepeat% sinon, ajouter ce \xrepeat
+		\advance\cnt at repeat by 1% incr\xE9menter le compteutr de \xrepeat\xA4\idx*\advance\xA4
+		\xloop at i% et chercher le prochain \xrepeat
+		}%
+}
+\let\xrepeat\fi
+\catcode`\@12
+\xloop a\xloop b\xloop 12\xrepeat c\xrepeat \xloop X\xrepeat\xrepeat\xA4\xA7*\xloop\xA7*\xrepeat\xA4/
+
+Cela fonctionne bien : tout ce qui se trouve entre le premier \xA7\xloop et son \xA7\xrepeat appari\xE9 (qui est le dernier ici) est bien affich\xE9. Maintenant, au lieu de simplement d\xE9tok\xE9nizer le texte de remplacement de \verb|\xiterate|, nous allons mimer avec cette macro ce que fait l'impl\xE9mentation \LaTeX{}. De plus, au lieu d'\xE9crire \verb|\xiterate|, il faudra \xE9crire partout dans le code \verb|\xiterate@<n>| de telle sorte que les imbrications de boucles ne red\xE9finissent pas cette macro et aient chacune la leur. Le nombre \verb|<n>| est le compteur d'imbrications stock\xE9 dans le compteur \verb|\cnt at nested|. Celui-ci est initialis\xE9 \xE0 0 en dehors de toute macro, incr\xE9ment\xE9 \xE0 chaque fois que \xA7\xloop est rencontr\xE9 et d\xE9cr\xE9ment\xE9 lors de la sortie de boucle.
+
+Bien entendu, pour former la macro \verb|\xiterate@<n>|, il va falloir faire appel \xE0 la paire \idx\csname\ldots\verb|\endcsname| et donc, alourdir sensiblement le code :
+
+\showcode/\catcode`\@11
+\newcount\cnt at repeat\xA4\idx*\newcount\xA4
+\newcount\cnt at nested
+\cnt at nested=0 % compteur d'imbrications
+\def\xloop{%\xA4\xA7*\xloop\xA4
+	\global\advance\cnt at nested by 1 % augmente le compteur d'imbrications\xA4\idx*\global\idx*\advance\xA4
+	\expandafter\def\csname xiterate@\number\cnt at nested\endcsname{}%
+	\cnt at repeat\z@% initialise le compteur de \xrepeat \xE0 0\xA4\idx*\z@\xA4
+	\xloop at i% aller \xE0 la macro \xloop at i
+}
+\long\def\xloop at i#1\xrepeat{%\xA4\xA7*\xrepeat\idx*\long\xA4
+	\expandafter\addtomacro\csname xiterate@\number\cnt at nested\endcsname{#1}%\xA4\defline\eee\xA7*\addtomacro\xA4
+	\expandafter\expandafter\expandafter\cnttimestocs\expandafter\expandafter\expandafter\xA4\xA7*\cnttimestocs\xA4
+		{\csname xiterate@\number\cnt at nested\endcsname}\xloop\cnt at loop\xA4\idx*\csname\idx*\endcsname\xA4
+	\ifnum\cnt at loop=\cnt at repeat\relax
+		\expandafter\firstoftwo\else\expandafter\secondoftwo\xA4\xA7*\firstoftwo\xA7*\secondoftwo\xA4
+	\fi
+		{\expandafter\eaddtomacro\csname xiterate@\number\cnt at nested\expandafter\endcsname\xA4\defline\bbb\xA7*\eaddtomacro\xA4
+			{\expandafter\expandafter\csname xiterate@\number\cnt at nested\endcsname\fi}%
+		%\expandafter\show\csname xiterate@\number\cnt at nested\endcsname\xA4\defline\aaa\idx*\show\xA4
+		\csname xiterate@\number\cnt at nested\endcsname\xA4\defline\ddd\xA4
+		\letname{xiterate@\number\cnt at nested}\relax\xA4\xA7*\letname\xA4
+		\global\advance\cnt at nested by -1\xA4\defline\ccc\idx*\global\idx*\advance\xA4
+		}
+		{\expandafter\addtomacro\csname xiterate@\number\cnt at nested\endcsname\xrepeat\xA4\xA7*\addtomacro\xA7*\xrepeat\xA4
+		\advance\cnt at repeat by 1 \xA4\idx*\advance\xA4
+		\xloop at i
+		}%
+}%
+\let\xrepeat\fi\xA4\xA7*\xrepeat\xA4
+\catcode`\@12
+
+\newcount\cntxx \cntxx=1 % compteur des lignes
+\newcount\cntyy\xA4\idx*\newcount\xA4
+\xloop\xA4\xA7*\xloop\xA4
+	\cntyy=1 % compteur des colonnes
+	\xloop\xA4\xA7*\xloop\xA4
+		(\number\cntxx,\number\cntyy)% affiche "(ligne,colonne)"
+		\ifnum\cntyy<5 % tant que colonne<5
+		\advance\cntyy1 % incr\xE9mente colonne
+		, % <- affiche ", "
+	\xrepeat% et recommence
+	\ifnum\cntxx<3 % tant que ligne<3
+	\advance\cntxx1 % incr\xE9mente ligne
+	\par % va \xE0 la ligne
+\xrepeat% et recommence\xA4\xA7*\xrepeat\xA4/
+
+L'utilisation de \verb|\csname...\endcsname| rend la lecture du code bien plus difficile puisqu'elle implique le d\xE9veloppement d'un pont d'\idx\expandafter pour faire naitre une macro puis pour acc\xE9der \xE0 son texte de remplacement d'une macro (lignes \nos\eee{} \xE0 \number\eee+3\relax). Malgr\xE9 cela, intrins\xE8quement, le code est identique \xE0 celui vu pr\xE9c\xE9demment. La seule diff\xE9rence se trouve entre les lignes \nos\bbb{} \xE0 \no\ccc. En effet, aux lignes \nos\bbb{}-\number\numexpr\bbb+1\relax{}, au lieu de d\xE9tok\xE9nizer la macro \verb|\xiterate@<n>| pour simplement l'afficher comme on le faisait en analyse pr\xE9alable, on ajoute au texte de remplacement de cette macro \xAB\idx\expandafter\xBB suivi du nom de la macro, c'est-\xE0-dire \verb|\xiterate@<n>| que l'on fait suivre d'un \verb|\fi|. Ainsi, le texte de remplacement de \verb|\xiterate@<n>| est finalement :
+
+\centrecode-<ce qui est entre \xloop et \xrepeat> \expandafter\xiterate@<n> \fi-
+
+On peut d'ailleurs prendre connaissance du texte de remplacement de la macro \verb|\xiterate@<n>| en d\xE9-commentant la ligne \no\aaa{} pour laisser \xE0 la primitive \idx\show l'\xE9crire dans le \idx[!log]{fichier} \verb|log|. Pour \verb|\xiterate at 1|, on obtient :
+
+\centrecode|\xiterate at 1=macro:->
+\cntyy =1
+\xloop\xA4\xA7*\xloop\xA4
+	(\number \cntxx ,\number \cntyy )
+	\ifnum \cntyy <5 ,
+	\advance \cntyy 1
+\xrepeat\xA4\xA7*\xrepeat\xA4
+\ifnum \cntxx <3
+	\advance \cntxx 1
+	\par
+	\expandafter\xiterate at 1
+\fi.|
+
+\noindent et pour \verb|\xiterate at 2| :
+
+\centrecode|\xiterate at 2=macro:->
+(\number \cntxx ,\number \cntyy )
+\ifnum \cntyy <5 ,
+\advance \cntyy 1
+	\expandafter\xiterate at 2
+\fi.|
+
+\noindent C'est exactement ce que fait l'impl\xE9mentation \LaTeX{} de la boucle \idx\loop\ldots\idx\repeat avec la macro \idx\iterate. En poursuivant le parall\xE8le avec la boucle \LaTeX{}, il suffit ensuite de lancer la macro \verb|\xiterate@<n>| \xE0 la ligne \no\ddd{} et une fois la boucle termin\xE9e, on rend \verb|\iterate@<n>| \idx\let-\xE9gale \xE0 \idx\relax \xE0 la ligne \no\number\numexpr\ddd+1\relax. Le tout se termine avec la d\xE9cr\xE9mentation du compteur d'imbrication \xE0 la ligne \no\ccc.
+
+\chapter{Une boucle \xAB foreach in \xBB}\label{doforeach}
+\section{Une premi\xE8re approche}
+Nous allons construire une boucle o\xF9 une \xAB variable \xBB --~qui sera comme pr\xE9c\xE9demment une s\xE9quence de contr\xF4le~-- prendra successivement toutes les valeurs d'une liste de valeurs, pas n\xE9cessairement num\xE9riques, s\xE9par\xE9es par des virgules et \xE0 chaque it\xE9ration, un code sera ex\xE9cut\xE9. La syntaxe de cette boucle, initi\xE9e par la macro \xA7\doforeach[|(], sera\footnote{La commande \texttt{\string\foreach} est d\xE9finie par le \idx[!pgf]{package} \xAB\texttt{pgf}\xBB et pour \xE9viter tout conflit, il vaut donc mieux choisir un autre nom.} :
+
+\centrecode-\doforeach\<macro>\in{<valeur 1>,<valeur 2>,...,<valeur n>}{<code>}-
+
+\noindent o\xF9 bien entendu, le \verb|<code>| peut contenir la \verb|\<macro>|.
+
+La m\xE9thode, relativement simple, va \xEAtre de lire toutes les valeurs une premi\xE8re fois, y ajouter \xE0 la fin une valeur reconnaissable (un \idx{quark}) et par la suite, lire les valeurs une par une jusqu'\xE0 ce qu'apparaisse le \idx{quark}. Nous mettons ici en \oe uvre la m\xE9thode recommand\xE9e pour lire une s\xE9rie d'arguments (voir page~\pageref{lire.arguments}) :
+
+\begin{algo}
+	\item lire la liste des valeurs et lui ajouter \xAB\verb-,\end at foreach,-\xBB, o\xF9 \verb-\end at foreach- est un \idx{quark}.
+
+	Sauvegarder le \verb|<code>| dans une macro (que nous appelons \verb|\loop at code|);
+	\item lire la valeur qui se trouve avant la virgule et l'assigner \xE0 \verb|\<macro>| ,
+	\item si \verb|\<macro>|=\verb-\end at foreach-, finir le processus ;
+	\item sinon ex\xE9cuter le \verb|<code>| et retourner en 2.
+\end{algo}
+
+Le point 1 sera d\xE9volu \xE0 une macro chapeau charg\xE9e de faire les assignations pr\xE9alables. Les autres points seront contenus dans une macro r\xE9cursive \xE0 argument d\xE9limit\xE9. Choisissons d'externaliser la macro r\xE9cursive (c'est-\xE0-dire de la d\xE9finir en dehors du texte de remplacement de la macro chapeau). Assurons-nous que la macro r\xE9cursive peut acc\xE9der \xE0 tous les arguments de la macro chapeau. Aucun probl\xE8me pour la liste des valeurs qu'elle lira comme argument au fur et \xE0 mesure. Le \verb|<code>| ne pose pas de probl\xE8me puisqu'il est sauvegard\xE9 dans \verb|\loop at code|. La variable \verb|\<macro>| n'\xE9tant pas sauvegard\xE9e, prenons comme solution de la transmettre comme argument \xE0 la macro r\xE9cursive : cette macro (qui n'est qu'un seul token) viendra comme premier argument non d\xE9limit\xE9, avant la liste des valeurs.
+
+\showcode/\catcode`\@11
+\def\end at foreach{\end at foreach}% d\xE9finit un quark\xA4\idx*{quark}\xA4
+\long\def\doforeach#1\in#2#3{%\xA4\idx*\long\xA4
+	\def\loop at code{#3}% assigne le <code> \xE0 \loop at code
+	% appel \xE0 \doforeach at i : mettre la macro #1 en premier, puis la liste de valeurs #2
+	\doforeach at i#1#2,\end at foreach,% ajouter \xE0 la fin ",\end at foreach,"
+	% une fois les boucles finies, neutraliser les macros d\xE9j\xE0 d\xE9finies
+	\let#1\relax \let\loop at code\relax
+}
+
+\long\def\doforeach at i#1#2,{% #1=\<macro>  #2=valeur courante\xA4\defline\aaa\idx*\long\xA4
+	\def#1{#2}% stocke la valeur en cours dans la \<macro>
+	\unless\ifx\end at foreach#1% si \end at foreach n'est pas atteint
+		\antefi% am\xE8ne le \fi ici\xA4\xA7*\antefi\xA4
+		\loop at code% ex\xE9cute le code
+		\doforeach at i#1% et recommencer
+	\fi
+}
+\catcode`@12
+\doforeach\x\in{a,bcd,{efg},hi}{\meaning\x.\par}/
+
+La ligne \no\aaa{} montre que la macro \verb|\doforeach at i| admet comme argument \emph{non d\xE9limit\xE9} \verb|#1| alors que la valeur en cours est l'argument \verb|#2| d\xE9limit\xE9 par la virgule. L'inconv\xE9nient, li\xE9 \xE0 la lecture d'argument, est que si une \verb|<valeur>| est constitu\xE9e d'un texte entre accolades, ce texte est d\xE9pouill\xE9 de ses accolades et assign\xE9 \xE0 la variable. Si l'on souhaitait \xE9viter cet \xE9cueil, il faudrait mettre un token (par exemple un \idx\relax) avant chaque \verb|<valeur>| et faire en sorte de manger ce \idx\relax avec \verb|\gobone| avant d'assigner la \verb|<valeur>| \xE0 la variable. Par souci de simplicit\xE9, cette man\oe uvre ne sera pas programm\xE9e.
+
+\begin{exercice}
+On pourrait vouloir modifier le s\xE9parateur de liste (qui est la virgule par d\xE9faut) pour mettre des nombres d\xE9cimaux dans la liste d'arguments, par exemple.
+
+Cr\xE9er une macro \xA7\defseplist dont l'argument est le s\xE9parateur voulu et modifier le code vu ci-dessus pour que la macro \xA7\doforeach tienne compte du s\xE9parateur ainsi d\xE9fini.
+\solution
+L'id\xE9e est de faire de \xA7\defseplist\verb|<s\xE9parateur>| une macro \xABenveloppante\xBB qui va d\xE9finir, \xE0 chaque fois qu'elle sera appel\xE9e, les deux macros \xA7\doforeach et \verb|\doforeach at i|, toutes les deux d\xE9pendantes de l'argument \verb|#1| de \xA7\defseplist. Dans le code d\xE9j\xE0 vu, la virgule va \xEAtre replac\xE9e par \verb|#1| et les autres \xAB\verb|#|\xBB qui s'appliquent aux arguments de \xA7\doforeach et \verb|\doforeach at i| vont \xEAtre doubl\xE9s pour tenir compte de l'imbrication des macros :
+
+\showcode/\catcode`\@11
+\def\end at foreach{\end at foreach}
+\def\defseplist#1{%\xA4\xA7*\defseplist\xA4
+	\long\def\doforeach##1\in##2##3{%\xA4\idx*\long\xA4
+		\def\loop at code{##3}% assigne le <code> \xE0 \loop at code
+		\doforeach at i##1##2#1\end at foreach#1% ajouter ",\end at foreach," et aller \xE0 \doforeach at i
+		% apr\xE8s \xEAtre sorti des boucles, neutraliser les macros d\xE9j\xE0 d\xE9finies
+		\let\loop at code\relax \let##1\relax
+	}%
+	\long\def\doforeach at i##1##2#1{%\xA4\idx*\long\xA4
+		\def##1{##2}% stocke la valeur en cours dans la \<macro>
+		\unless\ifx\end at foreach##1% si la fin n'est pas atteinte\xA4\tidx*{unless}\xA4
+			\antefi% am\xE8ne le \fi ici\xA4\xA7*\antefi\xA4
+			\loop at code% ex\xE9cute le code
+			\doforeach at i##1% et recommencer
+		\fi
+	}%
+}
+\defseplist{,}% d\xE9finit les macros avec le s\xE9parateur par d\xE9faut\xA4\xA7*\deseplist\xA4
+\catcode`@12
+
+\doforeach\x\in{a,bcd,efg}{Argument courant : "\x".\par}\medbreak\xA4\idx*\medbreak\xA4
+
+\defseplist{--}% s\xE9parateur "--"\xA4\xA7*\deseplist\xA4
+\doforeach\nn\in{4,19--0,5--8,575}{Nombre lu : "\nn"\par}/
+\end{exercice}
+
+\section{Rendre possible l'imbrication}
+Il nous reste \xE0 rendre possible l'imbrication de boucles \xA7\doforeach et pour cela, comme pr\xE9c\xE9demment avec \xA7\for et \xA7\xloop, nous allons d\xE9finir un compteur qui sera charg\xE9 de compter le niveau d'imbrication et qui fera partie du nom de la macro charg\xE9e de stocker le \verb|<code>|. Nous prendrons \xAB\verb|\loop at code@<n>|\xBB :
+
+\showcode/\catcode`\@11
+\newcount\cnt at nest \cnt at nest=0 % d\xE9finit et initialise le compteur d'imbrication\xA4\idx*\newcount\xA4
+\def\end at foreach{\end at foreach}
+
+\def\defseplist#1{%\xA4\xA7*\deseplist\xA4
+	\long\def\doforeach##1\in##2##3{%\xA4\idx*\long\xA4
+		\global\advance\cnt at nest1 % entr\xE9e de boucle : incr\xE9menter le compteur d'imbrication\xA4\idx*\global\xA4
+		\defname{loop at code@\number\cnt at nest}{##3}% assigne le <code> \xE0 \loop at code@<n>\xA4\xA7*\defname\xA4
+		\doforeach at i##1##2#1\end at foreach#1% ajouter ",\end at foreach," et aller \xE0 \doforeach at i
+		% une fois fini :
+		\let##1\empty% dans ce cas, neutraliser les macros d\xE9j\xE0 d\xE9finies\xA4\idx*\empty\xA4
+		\letname{loop at code@\number\cnt at nest}\empty%\xA4\xA7*\letname\xA4
+		\global\advance\cnt at nest-1 %sortie de boucle : d\xE9cr\xE9menter le compteur d'imbrication\xA4\idx*\global\idx*\advance\xA4
+	}%
+	\long\def\doforeach at i##1##2#1{%\xA4\idx*\long\xA4
+		\def##1{##2}% stocke la valeur en cours dans la \<macro>
+		\unless\ifx\end at foreach##1% tant que la fin n'est pas atteinte\xA4\tidx*{unless}\xA4
+			\antefi% am\xE8ne le \fi ici\xA4\xA7*\antefi\xA4
+			\csname loop at code@\number\cnt at nest\endcsname% ex\xE9cute le code\xA4\defline\aaa\xA4
+			\doforeach at i##1% et recommencer
+		\fi
+	}%
+}
+\catcode`@12
+\defseplist{,}\xA4\xA7*\deseplist\xA4
+
+\doforeach\xxx\in{1,2,3}{%
+	Ligne \xxx{} : \doforeach\yyy\in{a,b,c,d,e}{(\xxx,\yyy)}.\par
+}/
+
+Profitons \xE9galement de la simplicit\xE9 relative de ce code pour impl\xE9menter une fonctionnalit\xE9 qui pourrait \xEAtre d'un grand secours. Si la \xAB variable \xBB est d\xE9j\xE0 d\xE9finie lorsque la boucle est rencontr\xE9e, il serait judicieux de la sauvegarder pour la restaurer une fois la boucle termin\xE9e. Imaginons en effet qu'un utilisateur imprudent --~ou inconscient~-- nomme sa variable \idx\par par analogie avec le mot \xAB param\xE8tre \xBB et construise une boucle de cette fa\xE7on :
+
+\centrecode-\doforeach\par\in{a,b,c,y,z}{$\par_i$}-
+
+La primitive \idx\par serait silencieusement red\xE9finie \xE0 l'entr\xE9e de la boucle, pour \xEAtre rendue \idx\let-\xE9gale \xE0 \idx\relax \xE0 la fin ce qui aurait pour effet de rendre \TeX{} incapable de former un paragraphe. On imagine les d\xE9g\xE2ts, d'autant plus incompr\xE9hensibles que le tout se passe silencieusement. Il nous faut donc tester si la variable existe au d\xE9but de la boucle et si tel est le cas, la sauvegarder avec \idx\let pour la restaurer \xE0 la fin du processus.
+
+Il existe un test \tidx{ifdefined}\verb|\<commande>| de \idx\eTeX qui est vrai si la \verb|\<commande>| est d\xE9finie et faux sinon. Ce test ne modifie pas la table de hashage\footnote{Les tests \texttt{\textbackslash @ifundefined\{\codeelement{nom}\}} et \texttt{\textbackslash @ifdefinable\textbackslash\codeelement{nom}} de \LaTeX{} forment la s\xE9quence de contr\xF4le \texttt{\textbackslash\codeelement{nom}} \xE0 l'aide de \texttt{\textbackslash csname} et testent si elle est \xE9gale \xE0 \texttt{\textbackslash relax} auquel cas, la s\xE9quence de contr\xF4le est consid\xE9r\xE9e non d\xE9finie. Cette m\xE9thode pr\xE9sente deux gros inconv\xE9nients :
+\begin{itemize}
+	\item toute macro existante et \texttt{\textbackslash let}-\xE9gale \xE0 \texttt{\textbackslash relax} est consid\xE9r\xE9e par ces tests comme \xE9tant non d\xE9finie;
+	\item par l'utilisation de \texttt{\textbackslash csname}, une macro non d\xE9finie devient d\xE9finie et \texttt{\textbackslash let}-\xE9gale \xE0 \texttt{\textbackslash relax}. Un autre d\xE9g\xE2t collat\xE9ral est que la table de hashage est modifi\xE9e puisqu'une nouvelle macro est cr\xE9\xE9e.
+\end{itemize}}. Il existe aussi un test de \idx\eTeX un peu similaire \tidx{ifcsname}\verb|<nom d'une commande>|\idx\endcsname, qui forme la \verb|<commande>| comme le ferait \idx\csname puis teste si elle existe, sans modifier la table de hashage.
+
+La m\xE9thode sera ici de mettre \xE0 profit \tidx{ifdefined} pour tester si la variable existe et la sauvegarder dans \verb|\saved at var@<n>| si le test est positif. \xC0 la sortie de la boucle, il suffira de faire la man\oe uvre inverse pour restaurer la variable soit \xE0 \idx\relax, soit \xE0 ce qu'elle \xE9tait avant si elle existait auparavant.
+
+Dans le code ci-dessous, la variable a \xE9t\xE9 nomm\xE9e \xAB\verb|\par|\xBB ce qui est une chose \xE0 ne pas faire. M\xEAme si un dispositif a \xE9t\xE9 pr\xE9vu pour que \verb|\par| soit restaur\xE9e \xE0 la fin du processus, red\xE9finir une primitive, surtout aussi primordiale que \verb|\par|, \emph{est un danger qu'il faut \xE0 tout prix \xE9viter de courir}.
+
+\showcode/\catcode`\@11
+\newcount\cnt at nest \cnt at nest=0 % d\xE9finit et initialise le compteur d'imbrication\xA4\idx*\newcount\xA4
+\def\end at foreach{\end at foreach}
+\long\def\save at macro#1{% sauvegarde la macro #1\xA4\idx*\long\xA4
+	\ifdefined#1% si la macro #1 est d\xE9j\xE0 d\xE9finie...\xA4\tidx*{ifdefined}\xA4
+		\letname{saved at var@\number\cnt at nest}#1% ...la sauvegarder\xA4\xA7*\letname\xA4
+	\fi
+}
+\long\def\restore at macro#1{% restaure la macro #1\xA4\idx*\long\xA4
+% le \csname donne \relax si la sauvegarde n'a pas \xE9t\xE9 faite
+	\expandafter\let\expandafter#1\csname saved at var@\number\cnt at nest\endcsname
+}
+\def\defseplist#1{%\xA4\xA7*\deseplist\xA4
+	\long\def\doforeach##1\in##2##3{%\xA4\idx*\long\xA4
+		\global\advance\cnt at nest1 % entr\xE9e de boucle : incr\xE9menter le compteur d'imbrication\xA4\idx*\global\idx*\advance\xA4
+		\save at macro##1% sauvegarde la macro ##1
+		\defname{loop at code@\number\cnt at nest}{##3}% assigne le <code> \xE0 \loop at code@<n>\xA4\xA7*\defname\xA4
+		\doforeach at i##1##2#1\end at foreach#1% ajouter ",\end at foreach," et aller \xE0 \doforeach at i
+		% une fois fini, neutraliser la macro contenant le <code>
+		\letname{loop at code@\number\cnt at nest}\empty\xA4\idx*\empty\xA7*\letname\xA4
+		\restore at macro##1% restaurer la \<macro>
+		\global\advance\cnt at nest-1 % et d\xE9cr\xE9menter le compteur d'imbrication\xA4\idx*\global\xA4
+	}%
+	\long\def\doforeach at i##1##2#1{%\xA4\idx*\long\xA4
+		\def##1{##2}% stocke la valeur en cours dans la \<macro>
+		\unless\ifx\end at foreach##1% si la fin n'est pas atteinte\xA4\tidx*{unless}\xA4
+			\antefi% am\xE8ne le \fi ici\xA4\xA7*\antefi\xA4
+			\csname loop at code@\number\cnt at nest\endcsname% ex\xE9cute le code\xA4\defline\aaa\xA4
+			\doforeach at i##1% et recommencer
+		\fi%
+	}%
+}
+\catcode`@12
+\defseplist{,}\xA4\xA7*\deseplist\xA4
+\doforeach\par\in{a,b,c,y,z}{$\par_i$}
+
+\meaning\par% \par doit \xEAtre redevenu une primitive\xA4\idx*\meaning\xA4
+
+\doforeach\xxx\in{1,2,3}{%
+	Ligne \xxx{} : \doforeach\yyy\in{a,b,c,d,e}{(\xxx,\yyy)}.\par
+}/
+
+\section{Boucle \xE0 deux variables}
+Une am\xE9lioration de la macro \xA7\doforeach serait de d\xE9tecter si la variable est seule, comme envisag\xE9 pr\xE9c\xE9demment, ou si l'utilisateur souhaite avoir un \emph{couple} de variables auquel cas, il \xE9crirait :
+
+\centrecode-\doforeach\<macro1>/\<macro2>\in{x1/y1,x2/y2,...,xn/yn}{<code>}-
+
+\noindent Chacune des variables \verb|\<macro1>| et \verb|\<macro2>| prendrait successivement les valeurs appari\xE9es sp\xE9cifi\xE9es dans l'argument qui suit le \verb|\in|.
+
+L'id\xE9e va \xEAtre de se servir de la macro \xA7\ifin vue pr\xE9c\xE9demment pour tester si l'argument d\xE9limit\xE9 par \xAB\verb|\in|\xBB contient le caract\xE8re \xAB\verb|/|\xBB et agir en cons\xE9quence. Si le test est positif, il faut s'orienter vers une macro \xE0 argument d\xE9limit\xE9 du type \verb|#1/#2| qui s\xE9pare les deux variables. Nous allons donc, selon l'issue du test \verb|\ifin{#1}{/}|, nous orienter vers la macro vue pr\xE9c\xE9demment si le test est n\xE9gatif ou vers une macro \verb|\doforeach at ii| avec des arguments d\xE9limit\xE9s appropri\xE9s. Nous allons profiter de cette nouvelle fonctionnalit\xE9 pour am\xE9liorer et optimiser le code.
+\grandsaut
+
+En premier lieu, la macro \verb|\save at macro| effectuera \emph{dans tous les cas} la sauvegarde de la (ou des) variables avec \verb|\let|, que ces variables soient d\xE9finies ou pas. La raison de ce choix, qui implique de se passer du test \tidx{ifdefined}, r\xE9side dans le fait que la variable est rendue \verb|\let|-\xE9gale \xE0 \idx\relax \xE0 la fin du processus : cela sera \emph{aussi} le cas si la variable est une macro ind\xE9finie. En effet, si une macro $x$ est rendue \verb|\let|-\xE9gale \xE0 une macro $y$ non d\xE9finie, $x$ devient \xE9galement non d\xE9finie. Par la suite, si $y$ est rendue \verb|\let|-\xE9gale \xE0 $x$ o\xF9 la macro $x$ est construite via \idx\csname, la macro $y$ devient \verb|\let|-\xE9gale \xE0 \idx\relax
+
+\showcode/\let\foo=\djfhdsldv% \foo est rendue \let-\xE9gale \xE0 une macro ind\xE9finie
+a) \meaning\foo\par
+% puis \djfhdsldv est rendue \let-\xE9gale \xE0 \foo (ou \foo est construit avec \csname)
+\expandafter\let\expandafter\djfhdsldv\csname foo\endcsname
+b) \meaning\djfhdsldv/
+
+L'optimisation que nous pouvons envisager est d'\xE9viter que la macro  \idx\csname (qui est lente) ne se trouve dans une boucle comme c'\xE9tait le cas \xE0 la ligne \no\aaa{} du code pr\xE9c\xE9dent. Pour cela, nous allons donner le code \xE0 ex\xE9cuter comme argument des macros r\xE9cursives. L'appel initial aux macros r\xE9cursives aura donc la structure suivante :
+
+\centrecode-\doforeach at i{<code>}<var>x1,x2,...,xn,<quark>,-
+
+\noindent ou
+
+\centrecode-\doforeach at ii{<code>}<var1>/<var2>x1/y1,x2/y2,...xn/yn,<quark>/<quark>,-
+
+Ces macros ne liront \xE0 chaque it\xE9ration que le \verb|<code>|, la (ou le couple de) variable(s), ainsi que la valeur courante \verb|xi| ou le couple de valeurs courant \verb|xi/yi|. Par cons\xE9quent, l'appel r\xE9cursif sera de la forme
+
+\begin{centrage}
+	\small\verb|\doforeach at i{#1}#2|\quad ou\quad \verb|\doforeach at i{#1}#2/#3|
+\end{centrage}
+
+\noindent o\xF9 \verb|#2| est la variable et \verb|#2/#3| est le couple de variables. Comme les r\xE9cursivit\xE9s sont terminales, les valeurs sont prises dans le code qui reste \xE0 lire.
+
+Comme ces macros r\xE9cursives effectuent un test \verb|\ifx| \xE0 chaque it\xE9ration pour d\xE9terminer si le \idx{quark} marquant la fin des valeurs est atteint, nous devons nous garder de l'erreur qui consisterait \xE0 utiliser \xA7\antefi alors que le \verb|<code>| se situe en \xA7\antefi et \verb|\fi|. Il s'agirait d'une erreur, car si le \verb|<code>| contient un test, l'\xA7\antefi (dont l'argument est d\xE9limit\xE9 par \verb|\fi|) prendrait le \verb|\fi| du \verb|<code>| comme d\xE9limiteur et romprait l'appariement correct entre \verb|\ifx| et son \verb|\fi|.
+
+Enfin, il nous faut inventer un moyen de cr\xE9er la macro \xA7\doforeachexit[|(], que l'utilisateur peut \xE9crire dans le \verb|<code>| et qui termine pr\xE9matur\xE9ment toutes les boucles \xA7\doforeach en cours d'ex\xE9cution. Cette macro doit annuler l'appel r\xE9cursif vu ci-dessus. L'id\xE9e directrice est de modifier ces appels r\xE9cursifs de cette mani\xE8re :
+
+\begin{centrage}
+	\small\verb|\allow at recurse{\doforeach at i{#1}#2}|\par ou\par \verb|\allow at recurse{\doforeach at i{#1}#2/#3}|
+\end{centrage}
+
+\noindent La macro \verb|\allow at recurse| sera rendue \idx\let-\xE9gale \xE0 \xA7\identity au d\xE9but de la boucle pour permettre par d\xE9faut que l'appel r\xE9cursif se fasse. Si l'utilisateur ins\xE8re \xA7\doforeachexit dans le \verb|<code>|, \verb|\allow at recurse| doit \xEAtre modifi\xE9e pour que cette derni\xE8re mange tout ce qui reste. \xAB Tout \xBB signifie l'appel r\xE9cursif \emph{et} toutes les valeurs (ou couples de valeurs) restant \xE0 lire. Comme ce \xAB tout\xBB se termine forc\xE9ment par le \idx{quark} \verb|\end at foreach| et le s\xE9parateur qui ont \xE9t\xE9 ins\xE9r\xE9s par l'appel initial, une macro \verb|\fordib at recurse| \xE0 argument d\xE9limit\xE9 effectuant cette t\xE2che est facile \xE0 cr\xE9er :
+
+\centrecode-\long\def\fordib at recurse##1\end at foreach#1{}-
+
+\noindent Une fois tout ceci mis en place, la macro \xA7\doforeachexit n'a plus qu'\xE0 rendre \verb|\allow at recurse| \idx\let-\xE9gale \xE0 \verb|\fordib at recurse|.
+
+\showcode|\catcode`\@11
+\newcount\cnt at nest \cnt at nest=0 % d\xE9finit et initialise le compteur d'imbrication\xA4\idx*\newcount\xA4
+\def\end at foreach{\end at foreach}
+\long\def\save at macro#1#2{\letname{saved at var@\number\cnt at nest#1}#2}\xA4\idx*\long\xA7*\letname\xA4
+\long\def\save at macro@i#1/#2{\save at macro{a}#1\save at macro{b}#2}
+\long\def\restore at macro#1#2{%\xA4\idx*\long\xA4
+	\expandafter\let\expandafter#2\csname saved at var@\number\cnt at nest#1\endcsname
+}
+\long\def\restore at macro@i#1/#2{\restore at macro{a}#1\restore at macro{b}#2}\xA4\idx*\long\xA4
+\def\defseplist#1{%\xA4\xA7*\deseplist\xA4
+	\long\def\doforeach##1\in##2##3{%\xA4\idx*\long \xA7*\doforeach\idx*\long\xA4
+		\global\advance\cnt at nest1 % entr\xE9e de boucle : incr\xE9menter le compteur d'imbrication\xA4\idx*\global\idx*\advance\xA4
+		\global\let\allow at recurse\identity% permet l'appel r\xE9cursif plus bas\xA4\idx*\global\xA7*\identity\xA4
+		\ifin{##1}{/}% si ##1 contient "/"\xA4\xA7*\ifin\xA4
+			{\save at macro@i##1% sauvegarde les macros
+			\doforeach at ii% appeler la macro r\xE9cursive avec les arguments
+				{##3}% 1) code \xE0 ex\xE9cuter
+				##1%   2) variables sous la forme \<macro1>/\<macro2>
+				##2#1\end at foreach/\end at foreach#1% puis la liste ##2 suivie de
+				                                % ",\end at foreach/\end at foreach,"
+			\restore at macro@i##1% une fois sorti de toutes les boucles, restaurer les macros
+			}% si ##1 ne contient pas "/"
+			{\save at macro{}##1% sauvegarde la macro
+			\doforeach at i% appeler la macro r\xE9cursive
+				{##3}% mettre en premier le <code>
+				##1% puis la variable ##1 en 2e position
+				##2#1\end at foreach#1% enfin la liste ##2 suivie de ",\end at foreach,"
+			\restore at macro{}##1% une fois sorti de toutes les boucles, restaurer la macro
+			}%
+		\global\advance\cnt at nest-1 % d\xE9cr\xE9mente le compteur d'imbrications\xA4\idx*\global\idx*\advance\xA4
+	}%
+	% ##1 = code \xE0 ex\xE9cuter, ##2= variable, ##3=valeur courante
+	\long\def\doforeach at i##1##2##3#1{%\xA4\idx*\long\xA4
+		\ifx\end at foreach##3% si la fin est atteinte
+		\expandafter\gobone\else\expandafter\identity\fi% manger sinon ex\xE9cuter:\xA4\xA7*\identity\xA4
+			{\def##2{##3}% fait l'assignation \xE0 la variable
+			##1% le code puis
+			\allow at recurse{\doforeach at i{##1}##2}% recommencer
+			}%
+	}%
+	% ##1 = code \xE0 ex\xE9cuter, ##2/##3= variables, ##4/##5=valeurs courantes
+	\long\def\doforeach at ii##1##2/##3##4/##5#1{%\xA4\idx*\long\xA4
+		\ifx\end at foreach##4% si la fin est atteinte
+		\expandafter\gobone\else\expandafter\identity\fi% manger sinon ex\xE9cuter:\xA4\xA7*\identity\xA4
+			{\def##2{##4}\def##3{##5}% fait l'assignation des deux variables
+			##1% le code puis
+			\allow at recurse{\doforeach at ii{##1}##2/##3}% recommencer
+			}%
+	}%
+	% macro qui, si elle remplace \allow at recurse, annule l'appel r\xE9cursif
+	\long\def\forbid at recurse##1\end at foreach#1{}% tout manger jusqu'\xE0 "\end at foreach,"\xA4\idx*\long\defline\aaa\xA4
+}
+\def\doforeachexit{\global\let\allow at recurse\forbid at recurse}\xA4\idx*\global\xA4
+\catcode`\@12
+\defseplist{,}\xA4\xA7*\deseplist\xA4
+\doforeach\par\in{a,b,c,y,z}{$\par_i$}\medskip\xA4\idx*\medskip\xA4
+
+\doforeach\sujet/\terminaison\in{Je/e,Tu/es,Il/e,Nous/ons,Vous/ez,Ils/ent}
+	{\sujet\ programm\terminaison{} en \TeX\par}\medskip\xA4\idx*\medskip\xA4
+
+Les voyelles lues sont :
+\doforeach\ii\in{a,e,i,o,u,y}{\ii\if o\ii\doforeachexit\fi}.\medskip\xA4\idx*\medskip\xA4
+
+\doforeach\xx\in{a,b,c,d,e,f}
+	{\doforeach\ii\in{1,2,3,4}{\xx\ii{} \ifnum\ii=3 \doforeachexit\fi}\par}|
+
+\begin{exercice}
+La derni\xE8re boucle imbriqu\xE9e montre que \xA7\doforeachexit sort pr\xE9matur\xE9ment de toutes les boucles en cours.
+
+Comment faudrait-il modifier le code pour que \xA7\doforeachexit ne sorte pr\xE9matur\xE9ment \emph{que} de la boucle dans laquelle elle a \xE9t\xE9 appel\xE9e, sans modifier le d\xE9roulement des boucles de niveau sup\xE9rieur ?
+\solution
+Il faut que \verb|\forbid at recurse|, en plus de manger tout jusqu'\xE0 la fin de la liste, rende de nouveau possibles les appels r\xE9cursifs \xE0 venir dans d'\xE9ventuelles boucles m\xE8res. Par cons\xE9quent, elle doit redonner \xE0 \verb|\allow at recurse| l'\xE9quivalence avec \xA7\identity qu'elle a par d\xE9faut. La ligne \no\aaa{} doit donc \xEAtre
+
+\centrecode-\long\def\forbid at recurse##1\end at foreach#1{\global\let\allow at recurse\identity}-\medskip
+\end{exercice}\xA7*\doforeach[|)]\xA7*\doforeachexit[|)]%
+
+\chapter{Dimensions et boites}\idx*[|(]{dimension}
+Avec \TeX, tout ce qui touche de pr\xE9s ou de loin \xE0 la typographie a une \xE9troite proximit\xE9 avec la g\xE9om\xE9trie et le placement des boites qui elles-m\xEAmes, entretiennent de proches rapports avec les dimensions.
+
+Le parti a \xE9t\xE9 pris de pr\xE9senter les dimensions (fixes et \xE9tirables) dans un premier temps, quitte \xE0 ce que cette th\xE9orie, d\xE9nu\xE9e des objets auxquels elle s'applique, soit un peu r\xE9barbative. Une fois que ces outils et leurs propri\xE9t\xE9s ont \xE9t\xE9 d\xE9crits, les boites et les r\xE9glures seront examin\xE9es dans un deuxi\xE8me temps.
+
+\section{Les dimensions fixes}\idx*[|(]{dimension fixe}
+\idx*[!dimension|(]{registre}\begin{regle}
+Une dimension fixe est utilis\xE9e pour mesurer une longueur prise au sens g\xE9om\xE9trique du terme. \TeX{} dispose de 256 \idx[!dimension]{registre}s de dimension (\numprint{32768} avec \idx\eTeX), chacun capable d'h\xE9berger une dimension. Pour faire r\xE9f\xE9rence \xE0 l'un de ces registres, on utilise la primitive \idx\dimen suivie de son num\xE9ro (sous la forme d'un \verb|<entier>|).
+
+Il est possible de demander l'allocation d'un registre inutilis\xE9 avec la macro de plain-\TeX{} \idx\newdimen\verb|\<macro>|. La \verb|\<macro>|, d\xE9finie en coulisse par la primitive \idx\dimendef avec
+
+\centrecode-\global\dimendef\<macro>=<nombre>-
+
+sera par la suite \xE9quivalente \xE0 \idx\dimen\verb|<nombre>| o\xF9 le \verb|<nombre>| est celui du prochain registre libre au moment de l'allocation.
+
+Un \verb|<registre de dimension>| est donc soit une \verb|\<macro>| pr\xE9alablement d\xE9finie \xE0 l'aide de \idx\newdimen, soit \xAB\verb|\dimen<nombre>|\xBB o\xF9 \verb|<nombre>| est le num\xE9ro du registre de dimension auquel on souhaite faire r\xE9f\xE9rence.
+
+Pour assigner une dimension \xE0 un registre de dimension, la syntaxe est
+
+\centrecode-<registre de dimension>= <dimension>-
+
+\noindent o\xF9 le signe \verb|=| et l'espace qui le suit sont facultatifs. Pour lire la \verb|<dimension>|, le d\xE9veloppement maximal se met en marche et apr\xE8s d\xE9veloppement, une \verb|<dimension>| est :
+
+\begin{itemize}
+	\item une dimension explicitement \xE9crite, c'est-\xE0-dire un \verb|<nombre>| (entier) ou un nombre d\xE9cimal suivi d'espaces facultatifs et de deux lettres de catcode 11 ou 12 repr\xE9sentant une des unit\xE9s de dimensions qu'accepte \TeX{} \xE0 savoir \texttt{pt},  \texttt{pc}, \texttt{in}, \texttt{bp}, \texttt{cm}, \texttt{mm}, \texttt{dd}, \texttt{cc}, \texttt{sp}, \texttt{em} et \texttt{ex}. Le s\xE9parateur d\xE9cimal peut indiff\xE9remment \xEAtre le point ou la virgule pourvu que son catcode soit 12. La lecture de la dimension s'arr\xEAte au premier token qui suit les deux caract\xE8res d'unit\xE9. Si ce token est un espace, celui est absorb\xE9.
+	\item un \verb|<registre de dimension>|. Si ce registre est pr\xE9c\xE9d\xE9 d'un nombre d\xE9cimal sign\xE9, la dimension obtenue sera celle du registre multipli\xE9e par le nombre sign\xE9 ;\label{multiplication.dimension}
+	\item un \verb|<registre de ressort>| (voir la d\xE9finition \xE0 la section suivante) auquel cas, la dimension retenue est \xE9gale \xE0 la composante non \xE9tirable du registre de ressort. Si ce registre est pr\xE9c\xE9d\xE9 d'un nombre d\xE9cimal sign\xE9, la dimension obtenue sera la composante fixe du ressort multipli\xE9e par le nombre sign\xE9.
+\end{itemize}
+
+La valeur absolue maximale d'une \verb|<dimension>| est contenue dans le registre de dimension \idx\maxdimen et vaut \texttt{16383.99999pt}, ce qui repr\xE9sente \texttt{\convertunit{\maxdimen}{cm}cm}.
+\end{regle}
+
+Pour ses dimensions, \TeX{} n'est pas avare d'unit\xE9s\idx*[!table des unit\xE9s]{dimension}. Il en manipule 11 dont voici les d\xE9finitions :
+
+\begin{centrage}
+\small
+\begin{tabular}{c>\ttfamily cr@{${}={}$}lr@{${}={}$}l}
+	\idx*{unit\xE9!table} Unit\xE9 & \multicolumn1c{Abr\xE9viation} & \multicolumn2c{D\xE9finition} & \multicolumn2c{Exemple}\\\hline
+	point\idx*{unit\xE9!pt}\idx*{pt (unit\xE9)} & pt& \multicolumn2c{}&1 \verb|pt| & \showdim{1pt}\\
+	pica\idx*{unit\xE9!pc}\idx*{pc (unit\xE9)} & pc & \numprint[pc]1&\numprint[pt]{12} & 1 \verb|pc| & \showdim{1pc}\\
+	pouce\idx*{unit\xE9!in}\idx*{in (unit\xE9)} & in & \numprint[in]1&\numprint[pt]{72,27} & 1 \verb|in| & \showdim{1in}\\
+	gros point\idx*{unit\xE9!bp}\idx*{bp (unit\xE9)} & bp & \numprint[bp]{72}&\numprint[in]1 & 1 \verb|bp| & \showdim{1bp}\\
+	centim\xE8tre\idx*{unit\xE9!cm}\idx*{cm (unit\xE9)} & cm & \numprint[cm]{2,54}&\numprint[in]1 & 1 \verb|cm| & \showdim{1cm}\\
+	millim\xE8tre\idx*{unit\xE9!mm}\idx*{mm (unit\xE9)} & mm & \numprint[mm]{10}&\numprint[cm]1 & 1 \verb|mm| & \showdim{1mm}\\
+	point didot\idx*{unit\xE9!dd}\idx*{dd (unit\xE9)} & dd & \numprint[dd]{1157}&\numprint[pt]{1238} & 1 \verb|dd| & \showdim{1dd}\\
+	cic\xE9ro\idx*{unit\xE9!cc}\idx*{cc (unit\xE9)} & cc & \numprint[cc]1&\numprint[dd]{12} & 1 \verb|cc| & \showdim{1cc}\\
+	point d'\xE9chelle\idx*{unit\xE9!sp}\idx*{point d'\xE9chelle}\idx*{sp (unit\xE9)} & sp & \numprint[sp]{65536}&\numprint[pt]1 & $10^6$ \verb|sp| & \showdim{1000000sp}\\
+	cadrat\idx*{unit\xE9!em}\idx*{em (unit\xE9)} & em & \multicolumn2c{} & \verb|1em| & \showdim{1em}\\
+	hauteur d'\oe il\idx*{unit\xE9!ex}\idx*{ex (unit\xE9)} & ex & \multicolumn2c{} & \verb|1ex| & \showdim{1ex}\\\hline
+\end{tabular}
+\end{centrage}
+
+Les deux derni\xE8res unit\xE9s d\xE9pendent de la police utilis\xE9e et de sa taille. Historiquement, \verb|1em| est la largeur de la lettre \xABM\xBB, mais le cr\xE9ateur de la fonte peut en d\xE9cider autrement et donner au \verb|em| une valeur diff\xE9rente. Par exemple, dans la police en cours dans ce paragraphe, \verb|1em| vaut \texttt{\convertunit{1em}{mm}mm} alors que la largeur de la boite englobante de la lettre \xABM\xBB vaut {\setbox0=\hbox{M}\texttt{\convertunit{\wd0}{mm}mm}}.
+
+La hauteur d'\oe il, ou \verb|ex| est cens\xE9e repr\xE9senter la hauteur des lettres sans hampe, ni jambage ni signe diacritique. Dans la police en cours, \verb|1ex| vaut \texttt{\convertunit{1ex}{mm}mm} et la hauteur de la boite englobante de la lettre \xABx\xBB vaut \texttt{\setbox0=\hbox{x}\convertunit{\dimexpr\ht0 + \dp0 }{mm}mm}.
+\grandsaut
+
+Les \verb|<registres de dimension>|\idx*[!dimension|)]{registre} sont comme les autres registres que nous avons d\xE9j\xE0 vus (registres d'entiers ou de tokens) : ce ne sont que des sortes de pointeurs vers une zone de m\xE9moire o\xF9 sont \xE9crits les octets capables, selon un proc\xE9d\xE9 interne \xE0 \TeX, de stocker le contenu du registre. Par cons\xE9quent, dans le code source, un \verb|<registre de dimension>| ne peut \xEAtre \xE9crit seul \emph{que} lorsque \TeX{} s'appr\xEAte \xE0 lire une dimension ou lors d'une assignation. Dans les autres cas, la primitive d\xE9veloppable \idx\the, lorsqu'elle pr\xE9c\xE8de le registre, en donne le contenu sous forme de tokens de catcode 12\idx*{catcode!12 (autre)}. Lorsqu'on invoque \idx\the pour faire remonter le contenu d'un registre de dimension des entrailles de \TeX{}, on obtient toujours une dimension en points\idx*{unit\xE9!pt}\idx*{pt (unit\xE9)} o\xF9 les caract\xE8res d'unit\xE9 \xAB\verb|pt|\xBB ont un catcode de 12. La partie d\xE9cimale est toujours affich\xE9e et \xE9ventuellement r\xE9duite \xE0 un 0, et le s\xE9parateur d\xE9cimal est le point. Le nombre de chiffres est au maximum de 5 apr\xE8s la virgule :
+
+\showcode/\newdimen\dimA \newdimen\dimB% alloue deux registres de dimension\xA4\idx*\newdimen\xA4
+a) \dimA=59.5pt
+   \the\dimA\qquad% doit afficher 59.5pt\xA4\idx*\the\xA4
+b) \dimA=1.5cm
+   \the\dimA\qquad% convertit \xE0 l'affichage 1.5cm en pt
+c) \dimB=7pt % assigne 7pt \xE0 \dimB
+   \dimA\dimB% rend \dimA \xE9gal \xE0 dimB
+   \the\dimA\qquad 
+d) \dimA=6\dimB% rend \dimA \xE9gal \xE0 6 fois \dimB
+   \the\dimA\xA4\idx*\the\xA4/\grandsaut
+
+Bien qu'\xE9tant traduites en points, toutes ces dimensions ne sont que des multiples de l'unit\xE9 de longueur que \TeX{} manipule en interne, le \xAB \idx{point d'\xE9chelle} \xBB (abr\xE9viation \xAB\verb|sp|\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)}\xBB pour \xAB scale point \xBB\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)}), plus petite dimension que \TeX{} peut manipuler et dont la longueur vaut approximativement \hbox{$5{,}4\times10^{-9}$}~m\xE8tre (soit 5,4 nanom\xE8tres). C'est extr\xEAmement petit, de l'ordre de la dimension d'un petit virus. Cette dimension ins\xE9cable, bien \xE9videmment invisible \xE0 l'\oe il nu, donne aux calculs sur les longueurs de \TeX{} une grande pr\xE9cision qui restera tr\xE8s inf\xE9rieure \xE0 ce qui peut \xEAtre d\xE9cel\xE9 \xE0 l'\oe il nu, m\xEAme apr\xE8s plusieurs arrondis.
+
+\subsection{Op\xE9rations sur les dimensions}
+Comme pour les entiers, des op\xE9rations sont disponibles pour les dimensions via les primitives \idx[|etc]\advance\forbidindex\advance{} pour l'addition, \idx\multiply et \idx\divide pour la multiplication et la division par un entier.
+
+Pour calculer $(25\text{\ttfamily pt}\div4+1,72\text{\ttfamily pt})\times3$, voici comment nous pourrions partir d'une dimension de 25pt, la diviser par 4, ajouter 1.72pt et multiplier le tout par 3 :
+
+\showcode|\newdimen\foo\xA4\idx*\newdimen\xA4
+\foo=25pt % assigne 25pt au registre \foo
+\divide\foo 4 % le multiplie par 4\xA4\idx*\divide\xA4
+\advance\foo1.72pt % lui ajoute 1.72pt\xA4\idx*\advance\xA4
+\multiply\foo3 % le multiplie par 3\xA4\idx*\multiply\xA4
+\the\foo% affiche la dimension obtenue\xA4\idx*\the\xA4|
+
+\begin{exercice}
+\xC9crire une macro \xA7\removept qui retire l'unit\xE9 d'une dimension explicite obtenue avec \idx\the. Si la partie d\xE9cimale est nulle, elle ne sera pas affich\xE9e.
+
+\solution
+Le premier r\xE9flexe est d'\xE9crire une macro \xE0 argument d\xE9limit\xE9 par \xAB\verb|pt|\xBB :
+
+\centrecode-\def\removept#1.#2pt{#1\ifnum#2>0 .#2\fi}-\xA7*\removept
+
+Mais cela ne fonctionnera pas puisque les caract\xE8res \xAB\verb|pt|\xBB du \idx{texte de param\xE8tre} n'ont pas le catcode 12\idx*{catcode!12 (autre)}. Il faut donc ruser un peu pour d\xE9finir la macro. Nous pouvons par exemple utiliser une macro temporaire pour stocker \xAB\verb|\def\removept#1.#2pt|\xBB o\xF9 les d\xE9limiteurs \xAB\verb|pt|\xBB ont un catcode \xE9gal \xE0 12. Cette macro temporaire sera d\xE9finie par un \idx\edef pour d\xE9velopper \xAB\idx\string\verb| p|\xBB et \xAB\verb|\string t|\xBB qui donnent les caract\xE8res \xAB\verb|pt|\xBB de catcode 12\idx*{catcode!12 (autre)} :
+
+\showcode/\begingroup% ouvrir un groupe
+	\edef\temp{\endgroup\def\noexpand\removept##1.##2\string p\string t}%\xA4\xA7*\removept\idx*\string\xA4
+\temp{#1\ifnum#2>0 .#2\fi}% et le fermer avant de d\xE9finir \removept
+\newdimen\foo\xA4\idx*\newdimen\xA4
+a) \foo=15pt \expandafter\removept\the\foo\qquad\xA4\idx*\the\xA4
+b) \foo=3.14pt \expandafter\removept\the\foo\xA4\xA7*\removept\xA4/
+
+L'astuce consiste \xE0 inclure le \idx\endgroup dans le texte de remplacement de \verb|\temp| de telle sorte que lorsque \verb|\temp| se d\xE9veloppe puis s'ex\xE9cute, ce \idx\endgroup provoque la destruction de cette macro temporaire avant m\xEAme d'avoir fini de lire son texte de remplacement.
+
+Il est naturel de cr\xE9er la macro \xA7\dimtodec qui transforme un registre de dimension en nombre d\xE9cimal :
+
+\showcode/\def\dimtodec{\expandafter\removept\the}\xA4\xA7*\dimtodec\xA7*\removept\xA4
+\newdimen\foo\xA4\idx*\newdimen\xA4
+a) \foo=15pt \dimtodec\foo \qquad
+b) \foo=3.14pt \dimtodec\foo\xA4\xA7*\dimtodec\xA4/
+\end{exercice}
+
+\subsection{La primitive \texttt{\textbackslash dimexpr}}
+La primitive \idx\dimexpr\label{dimexpr} de \idx\eTeX{} est aux calculs sur dimensions ce que \idx\numexpr est aux calculs sur les entiers. Elle rend possibles des calculs sur les dimensions de \TeX{} sans passer par les registres de dimension et les primitives \idx\advance, \idx\multiply et \idx\divide qui donnent un code assez fastidieux. 
+
+\begin{regle}
+La primitive \idx\dimexpr de \idx\eTeX{} doit \xEAtre suivie d'un enchainement d'op\xE9rations sur des dimensions qui est \xE9valu\xE9 selon les r\xE8gles math\xE9matiques habituelles : parenth\xE8ses, op\xE9rations (\verb|+|, \verb|*|, \verb|/|), priorit\xE9s. Cette primitive poss\xE8de les propri\xE9t\xE9s suivantes :
+
+\begin{itemize}
+	\item tout comme \idx\numexpr, \idx\dimexpr amorce un d\xE9veloppement maximal pour \xE9valuer l'\verb|<expression>| qui la suit. L'\verb|<expression>| prend fin au premier caract\xE8re qui ne peut faire partie d'un calcul sur les dimensions. La primitive \idx\relax peut marquer la fin d'une \verb|<expression>| et dans ce cas, elle est absorb\xE9e par \idx\dimexpr;
+	\item les espaces dans l'\verb|<expression>| sont ignor\xE9s ;
+	\item dans l'\verb|<expression>|, une \verb|<dimension>| ne peut \xEAtre multipli\xE9e ou divis\xE9e (avec \verb|*| ou \verb|/|) que par un \emph{entier}. Dans ce cas, l'entier \emph{doit} \xEAtre l'op\xE9rateur c'est-\xE0-dire qu'il doit suivre la dimension. On doit donc \xE9crire
+	
+	\begin{centrage}\verb-<dimension>*<entier>- ou \verb-<dimension>/<entier>-\end{centrage}
+	\item une \verb|<expression>| \xE9valu\xE9e par \idx\dimexpr est du m\xEAme type qu'un registre de dimension, il s'agit donc d'une repr\xE9sentation \emph{interne} d'une dimension. On peut convertir cette repr\xE9sentation interne en caract\xE8res de catcode 12\idx*{catcode!12 (autre)} en faisant pr\xE9c\xE9der \idx\dimexpr de la primitive d\xE9veloppable \idx\the.
+\end{itemize}
+\end{regle}
+
+Voici quelques exemples o\xF9 la primitive \idx\dimexpr est mise \xE0 contribution :
+
+\showcode|a) \the\dimexpr 1cm + 0.5cm\relax \qquad\xA4\idx*\dimexpr\xA4
+b) \the\dimexpr 1pt + 1pt\relax \qquad\xA4\idx*\the\xA4
+c) \the\dimexpr 1pt + 2pt * 3\relax\qquad
+d) \the\dimexpr (1pt + 2pt) * 3\relax\qquad
+e) \the\dimexpr (1.2pt + 0.8pt) * 5\relax\qquad
+f) \newdimen\foo \foo=15pt \xA4\idx*\newdimen\xA4
+   \the\dimexpr\foo-(\foo + 1pt) / 4\relax|
+
+\subsection{Les limites du calcul sur les dimensions}\label{arrondis.sur.dimensions}\idx*[|(]{dimension!arrondi}\idx*[|(]{arrondi (dimension)}
+Tout semble se passer pour le mieux et il serait tentant de penser qu'une fois lib\xE9r\xE9e de son unit\xE9 en \verb|pt|, une dimension se comporte exactement comme un nombre d\xE9cimal tandis que de son c\xF4t\xE9, \idx\dimexpr joue le r\xF4le de machine \xE0 calculer. La simple addition ci-dessous va temp\xE9rer ce jugement :
+
+\showcode/\the\dimexpr0,7pt + 0.4pt\relax\xA4\idx*\the\idx*\dimexpr\xA4/
+
+\Qu e se passe-t-il et pourquoi le simple calcul \xAB\texttt{0,7pt + 0.4pt}\xBB ne donne-t-il pas comme r\xE9sultat \texttt{1.1pt}? Les calculs de dimensions seraient-ils bogu\xE9s ? La r\xE9ponse est bien \xE9videmment non, mais c'est le revers de la m\xE9daille : puisque toutes les dimensions sont converties en \xAB\verb|sp|\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)}\xBB en interne pour effectuer les calculs puis sont \xE0 nouveau converties en \xAB\verb|pt|\xBB pour le r\xE9sultat, des arrondis sont in\xE9vitablement faits lors de ces deux conversions. Il faut donc s'attendre \xE0 ce que ces arrondis viennent dans certains cas se cumuler d\xE9favorablement. Voici l'explication de l'erreur constat\xE9e :
+
+\begin{itemize}
+	\item \verb|0,7pt| vaut $0,7\times\numprint{65536}=\numprint[sp]{45875.2}$ qui est arrondi \xE0 \numprint[sp]{45875}\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)};
+	\item \verb|0.4pt| vaut $0.4\times\numprint{65536}=\numprint[sp]{26214.4}$ qui est arrondi \xE0 \numprint[sp]{26214};
+	\item en tenant compte des arrondis, la somme vaut $\numprint{45875}+\numprint{26214}=\numprint[sp]{72089}$;
+	\item convertie en pt, cette somme vaut $\numprint{72089}\div65536=\numprint{1,09999084473}$ et \TeX{} donne 5 chiffres apr\xE8s la virgule ce qui fait bien \numprint[pt]{1.09999}.
+\end{itemize}
+
+Le r\xE9sultat attendu, \verb|1.1pt| vaut $\numprint{1.1}\times{65536}=\numprint[sp]{72089.6}$ qui serait arrondi par \TeX{} \xE0 \numprint[sp]{72090}\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)}.
+
+Si une dimension est consid\xE9r\xE9e comme une mesure de ce qui doit \xEAtre affich\xE9, ces erreurs d'arrondis sont absolument insignifiantes puisqu'invisibles \xE0 l'\oe il nu; insistons sur le fait qu'il ne s'agit ici que d'une minuscule erreur d'\verb|1sp|\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)} c'est-\xE0-dire de quelques nanom\xE8tres ! Mais pour le programmeur, c'est la douche froide et c'est l'assurance que les dimensions ne peuvent pas jouer le r\xF4le de nombres d\xE9cimaux pris en tant que nombres \emph{math\xE9matiques}, car une erreur sur une simple addition est inacceptable. On peut donc affirmer que \TeX{} ne dispose de rien qui pourrait tenir lieu de nombres d\xE9cimaux comme en disposent les autres langages. Bien \xE9videmment, on peut \emph{programmer} le fonctionnement de nombres d\xE9cimaux (en virgule fixe ou flottante) avec les outils de base de \TeX{} que sont les entiers et les 4 op\xE9rations. Construire des op\xE9rations sur ces nombres est extr\xEAmement fastidieux\footnote{L'extension \xAB\texttt{\idx*{package!fp}fp}\xBB (pour \xABfixed point\xBB) a relev\xE9 ce d\xE9fi. Cette extension est programm\xE9e en \TeX{} et utilise les compteurs pour parvenir \xE0 ses fins. Elle d\xE9finit et manipule des nombres en virgule \emph{fixe} avec une partie enti\xE8re et une partie d\xE9cimale de 18 chiffres chacune et effectue toutes les op\xE9rations arithm\xE9tiques et scientifiques habituelles sur ces nombres en virgule fixe (puissances, exponentielles, logarithmes, lignes trigonom\xE9triques, tests, nombres pseudoal\xE9atoires, etc.). Ainsi, il est tr\xE8s facile de calculer que
+
+\[\frac{\mathrm e^4 \ln\left(1+\cos\frac\pi7\right)}{1-3\arctan(0.35)}+4\sqrt[3]{5+\sqrt{2}}\approx-3491.19785321755\mathbf{4299238}
+\]
+
+Du fait d'arrondis successifs dans cette expression complexe, les d\xE9cimales en gras sont fausses% et devraient \xEAtre 5016987
+.}\idx*[|)]{dimension!arrondi}\idx*[|)]{arrondi (dimension)}. Il faut mentionner la macro purement d\xE9veloppable \xA7\decadd, programm\xE9e en annexe (voir page~\pageref{decadd}), qui permet d'additionner de fa\xE7on \emph{exacte} deux nombres d\xE9cimaux sign\xE9s.
+
+Il est primordial de comprendre qu'une dimension et un nombre entier ne sont que deux facettes d'une m\xEAme chose : puisque tous les calculs se font en nombre entier de points d'\xE9chelle\idx*{point d'\xE9chelle}, une dimension en \TeX{} n'est en r\xE9alit\xE9 que le nombre \emph{entier} de \verb|sp|\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)} qu'elle repr\xE9sente !
+
+\begin{regle}
+Toutes les dimensions fixes que \TeX{} manipule sont converties en interne en le nombre \emph{entier} de \idx*{point d'\xE9chelle}points d'\xE9chelle (\verb|sp|\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)}) qu'elles repr\xE9sentent. Une dimension s'apparente donc \xE0 un entier.
+
+Si \TeX{} est \xE0 un endroit o\xF9 il s'attend \xE0 lire un \verb|<nombre>| entier et qu'il lit un \verb|<registre de dimension>|, il convertit la dimension contenue dans le registre en \xAB \idx{entier contraint} \xBB qui est le nombre de \verb|sp|\idx*{sp (unit\xE9)}\idx*{unit\xE9!sp} qu'elle repr\xE9sente. Cet entier contraint est le \verb|<nombre>| qui sera  pris en compte.
+\end{regle}
+
+Constatons-le avec ce code o\xF9 la primitive \idx\number qui, attendant un nombre entier, force la conversion de la dimension en \idx{entier contraint} :
+
+\showcode/a) \newdimen\foodim \foodim=1cm \number\foodim\relax\qquad\xA4\idx*\newdimen\xA4
+b) \number\dimexpr 0.7pt + 0.4pt\relax\qquad\xA4\idx*\number\xA4
+c) \number\dimexpr 1.1pt\relax/
+
+\begin{exercice}
+La macro \verb|\for|, programm\xE9e \xE0 la page~\pageref{for}, ne peut manipuler que des nombres \emph{entiers}.
+
+Sur le mod\xE8le de \xA7\for, cr\xE9er une macro \xA7\FOR o\xF9 les nombres (borne mini, maxi et incr\xE9ment) peuvent \xEAtre d\xE9cimaux.
+
+On utilisera le test \tidx{ifdim}, de syntaxe
+
+\centrecode-\ifdim<dimension1><signe de comparaison><dimension2>
+	<code vrai>
+\else
+	<code faux>
+\fi-
+
+qui est aux \verb|<dimensions>| ce que le test \verb|\ifnum| est aux entiers.
+\solution
+Il y a peu de changements \xE0 faire. Il faudra remplacer les tests \tidx{ifnum} par \tidx{ifdim} et rajouter l'unit\xE9 \verb|pt| lorsque c'est n\xE9cessaire.
+
+\showcode/\catcode`\@11
+\def\FOR#1=#2to#3\do#4#{%
+	\ifempty{#4}\xA4\xA7*\ifempty\xA4
+		{\let\FOR at increment\z@}
+		{\edef\FOR at increment{\the\dimexpr#4pt\relax}}% lit et normalise l'argument optionnel
+	\ifdim\FOR at increment=\z@% s'il est nul,\xA4\idx*\z@\xA4
+		\edef\FOR at increment{% le red\xE9finir \xE0 -1pt (si #3<#2) et 1pt sinon
+			\ifdim\dimexpr#3pt-#2pt\relax<\z@ -1\else 1\fi pt\xA4\idx*\numexpr\idx*\z@\xA4
+		}% \FOR at increment vaut donc 1 ou -1
+	\fi
+	\ifdim\dimtodec\dimexpr#3pt-#2pt\relax\dimexpr\FOR at increment\relax<\z@\xA4\defline\aaa\xA4
+		\expandafter\gobone% si argument optionnel incompatible, manger le {<code>}
+	\else
+		\edef#1{\dimtodec\dimexpr#2pt\relax}% initialise la \<macro>
+		\edef\macro at args{% d\xE9finit et d\xE9veloppe les arguments \xE0 passer \xE0 \FOR at i
+			%#1=nom de la macro r\xE9cursive :
+			\expandafter\noexpand\csname FOR at ii@\string#1\endcsname\xA4\idx*\csname\idx*\endcsname\idx*\string\xA4
+			\ifdim\FOR at increment<\z@ <\else >\fi% #2=signe de comparaison\xA4\idx*\z@\xA4
+			{\FOR at increment}% #3=incr\xE9ment
+			\noexpand#1% #4=\<macro>\xA4\idx*\noexpand\xA4
+			{\the\dimexpr#3pt\relax}% #5=dimension n2\xA4\idx*\number\idx*\numexpr\xA4
+		}%
+		\antefi% externalise la ligne ci-dessous de la port\xE9e du test\xA4\xA7*\antefi\xA4
+		\expandafter\FOR at i\macro at args% appelle \FOR at i avec les arguments d\xE9finis ci-dessus
+	\fi
+}
+
+% #1=nom de la macro r\xE9cursive de type "\FOR at ii@\<macro>"
+% #2=signe de comparaison  % #3=incr\xE9ment
+% #4=\<macro>  % #5=dimension n2  % #6=<code> \xE0 ex\xE9cuter
+\long\def\FOR at i#1#2#3#4#5#6{%\xA4\idx*\long\xA4
+	\def#1{% d\xE9finit la sous macro r\xE9cursive
+		\unless\ifdim#4pt#2#5\relax% tant que la \<macro> variable n'a pas d\xE9pass\xE9 n2\xA4\tidx*{unless}\xA4
+			\afterfi{% rendre la r\xE9cursivit\xE9 terminale\xA4\xA7*\afterfi\idx*{r\xE9cursivit\xE9!terminale}\xA4
+				#6% ex\xE9cute le code\xA4\defline\bbb\xA4
+				\edef#4{\dimtodec\dimexpr#4pt+#3\relax}% incr\xE9mente la \<macro>
+				#1% recommence
+			}%
+		\fi
+	}%
+	#1% appelle la sous-macro r\xE9cursive\xA4\defline\ccc\xA4
+}%
+\def\exitFOR#1{% #1=\<macro> correspondant \xE0 la boucle de laquelle on veut sortir\xA4\xA7*\exitFOR\xA4
+	\defname{FOR at ii@\string#1}{}%\xA4\idx*\csname\idx*\endcsname\idx*\string\xA7*\defname\xA4
+}
+
+\def\ifexitFOR#1{% envoie vrai si on est pr\xE9matur\xE9ment sorti de la boucle de \<macro> #1\xA4\xA7*\ifexitFOR\xA4
+	% si la macro r\xE9cursive est \empty
+	\expandafter\ifx\csname FOR at ii@\string#1\endcsname\empty\xA4\idx*\string\idx*\empty\xA4
+		\expandafter\firstoftwo% c'est qu'on est sortir pr\xE9matur\xE9ment, renvoyer "vrai"\xA4\xA7*\firstoftwo\xA4
+	\else
+		\expandafter\secondoftwo% sinon, renvoyer "faux"\xA4\xA7*\secondoftwo\xA4
+	\fi
+}
+\catcode`\@=12
+a) \FOR\xx=1.5 to -5\do-1{"\xx" }\par
+
+b) \FOR\ii=1 to 2.742\do.25{"\ii" }\par
+
+c) \FOR\ii=0 to 1\do0.1{"\ii" \ifdim\ii pt>0.5pt \exitFOR\ii\fi}\xA4\xA7*\FOR\xA4/
+
+La ligne \no\aaa{} m\xE9rite tout de m\xEAme quelques explications. Il s'agit de trouver le signe de
+
+\[(\hbox{\verb|#3|}-\hbox{\verb|#2|})\times\hbox{\verb|\for at increment|}\]
+
+Pour calculer cette expression sous forme de dimension, nous avons tout d'abord transform\xE9 \verb|#3-#2| en un d\xE9cimal sans unit\xE9 avec la macro \xA7\dimtodec. La macro \verb|\for at increment| est transform\xE9e en une dimension de type \verb|<registre>| avec \idx\dimexpr. Le test \tidx{ifdim} voit donc \verb|<x><registre de dimension>| o\xF9 \verb|<x>| est un d\xE9cimal sign\xE9. Comme l'explique la r\xE8gle vue pr\xE9c\xE9demment, le tout forme une \verb|<dimension>| \xE9gale au produit de \verb|#3-#2| par \verb|\for at increment|.
+
+Comme le montre le cas c, additionner \xE0 chaque it\xE9ration l'incr\xE9ment \xE0 la dimension pr\xE9c\xE9dente conduit parfois \xE0 des erreurs d'arrondi g\xEAnantes. Pour une addition d\xE9cimale \emph{exacte}, voir en annexe la macro \xA7\decadd, page~\pageref{decadd}.
+\end{exercice}
+
+\subsection{\xC9tendre les calculs sur les dimensions}
+Puisqu'il n'est pas question d'\xE9crire une extension aussi complexe que \verb|fp|, nous allons accepter les erreurs d'arrondis dues \xE0 la m\xE9thode de calcul sur les dimensions. Aussi, nous allons confondre dimension en \verb|pt| sans unit\xE9 et nombre d\xE9cimal; en effet, passer de l'une \xE0 l'autre est facile. Il suffit d'appeler la macro \xA7\dimtodec pour le sens \emph{dimension vers d\xE9cimal} ou d'ajouter l'unit\xE9 \verb|pt| pour le sens inverse.
+
+Nous allons essayer de tirer parti de \idx\dimexpr et des r\xE8gles que nous avons vues pour \xE9tendre un peu les possibilit\xE9s de calcul de \TeX{} sur les nombres d\xE9cimaux. Si l'addition et la soustraction op\xE8rent sur \emph{deux} nombres d\xE9cimaux, il n'en est pas de m\xEAme pour la multiplication et la division qui ne sont capables de multiplier ou diviser par un \emph{entier}.
+
+\subsubsection{Multiplier deux d\xE9cimaux}
+Essayons tout d'abord de programmer une macro \xA7\decmul qui permet de multiplier deux nombres \emph{d\xE9cimaux}, chacun se trouvant dans un argument.
+
+Nous allons exploiter le fait que \verb|<d\xE9cimal><registre de dimension>| est vue comme une dimension \xE9gale au produit des deux quantit\xE9s.
+
+\showcode/\newdimen\foo\xA4\idx*\newdimen\xA4
+\foo=15.2pt \foo=1.5\foo \the\foo% vaut 15.2*1.5\xA4\idx*\the\xA4/
+
+Aux erreurs d'arrondi pr\xE8s auxquelles nous nous sommes r\xE9sign\xE9s, le r\xE9sultat est correct. Voici donc comment programmer la macro \xA7\decmul\label{decmul} :
+
+\showcode/\catcode`\@11
+\newdimen\dim at a\xA4\idx*\newdimen\xA4
+\def\decmul#1#2{%\xA4\xA7*\decmul\xA4
+	\dim at a=#2pt    % range la dimension #2pt dans le registre de dimension
+	\dim at a=#1\dim at a% multiplier le registre par le d\xE9cimal #1
+	\dimtodec\dim at a% convertir la dimension en d\xE9cimal\xA4\xA7*\dimtodec\xA4
+}
+\catcode`\@12
+a) \decmul{15.2}{1.5}\qquad
+b) \decmul{48.2}{.375}\xA4\xA7*\decmul\xA4/
+
+\begin{exercice}
+La macro \xA7\decmul programm\xE9e ci-dessus n'est pas purement d\xE9veloppable. Utiliser la primitive \idx\dimexpr pour qu'elle le devienne.
+\solution
+La m\xE9thode va \xEAtre de donner \xE0 \xA7\dimtodec non pas un vrai registre de dimension, mais une expression \xE9valu\xE9e par \idx\dimexpr, puisque cette primitive est du m\xEAme type qu'un registre de dimension :
+
+\centrecode-\dimtodec\dimexpr<expression>\relax-
+
+En ce qui concerne l'\verb|<expression>|, nous allons utiliser la m\xEAme m\xE9thode vue ci-dessus, \xE0 savoir \verb|#1<registre>| o\xF9 le \verb|<registre>| sera remplac\xE9 par \idx\dimexpr\verb|#2\relax|. Cela donne :
+
+\showcode/\def\decmul#1#2{\dimtodec\dimexpr#1\dimexpr#2pt\relax\relax}\xA4\xA7*\decmul \xA7*\dimtodec\idx*\dimexpr\xA4
+
+a) \decmul{15.2}{1.5}\qquad
+b) \edef\foo{\decmul{48.2}{.375}}\meaning\foo\xA4\xA7*\decmul\xA4/
+\end{exercice}
+
+\subsubsection{Diviser par un d\xE9cimal}
+Si nous souhaitons \xE9crire une macro analogue \xA7\decdiv[|(]\verb|{<nba>}{<nbb>}| qui effectue la division du d\xE9cimal \verb|<nba>| par le d\xE9cimal \verb|<nbb>|, l'astuce consiste \xE0 \xE9valuer avec \idx\numexpr l'entier suivant :
+
+\[
+\frac{\text{\texttt{\codeelement{nba}pt}}\times\text{\ttfamily 1pt}}{\text{\texttt{\codeelement{nba}pt}}}
+\]
+
+\noindent Comme \idx\numexpr s'attend \xE0 des op\xE9rations sur des entiers, chaque dimension, pr\xE9alablement mise sous forme de registre avec \verb|\dimexpr|, sera convertie en entier contraint. Le risque de d\xE9passement de l'entier maximal au num\xE9rateur est improbable, car lorsque \idx\numexpr (tout comme \idx\dimexpr) effectue une multiplication imm\xE9diatement suivie d'une division, les calculs internes se font sur 64 bits et non sur 32.
+
+Une fois cet entier calcul\xE9, nous lui donnerons l'unit\xE9 \verb|sp|\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)} et \xE9valuerons le tout avec \idx\dimexpr. Le r\xE9sultat, expurg\xE9 de son unit\xE9 avec \xA7\dimtodec, donnera le quotient cherch\xE9.
+
+Pour \xE9viter un \idx\dimexpr inutile, la dimension \verb|1pt|, qui vaut \verb|65536sp|, a \xE9t\xE9 directement convertie en l'entier contraint \verb|65536| :
+
+\showcode|\def\decdiv#1#2{% divise le d\xE9cimal #1 par le d\xE9cimal #2\xA4\xA7*\decdiv\xA4
+	\dimtodec\xA4\xA7*\dimtodec\idx*\dimexpr\idx*\numexpr\xA4
+	\dimexpr
+		\numexpr
+			\dimexpr #1pt \relax * 65536 / \dimexpr #2pt \relax
+		\relax
+		sp\xA4\idx*{sp (unit\xE9)}\idx*{unit\xE9!sp}\idx*{sp (unit\xE9)}\xA4
+	\relax
+}
+
+1) \decdiv{4.5}{0.075}\qquad% doit donner 60
+2) \decdiv{8}{0.1}\qquad% doit donner 80
+3) \decdiv{3.14}{1.6}\qquad% doit donner 1.9625
+4) \decdiv{687.59829}{5.29871}\qquad% doit donner 129.76706
+4) \edef\foo{\decdiv{0.37}{2.5}}\foo% doit donner 0.148\xA4\xA7*\decdiv\xA4|
+
+Ici encore, il ne s'agit que d'arithm\xE9tique \TeX ienne, c'est-\xE0-dire que comme avec \xA7\decmul, les r\xE9sultats sont entach\xE9s d'erreurs d'arrondis et donc, ces macros ne pourront \xEAtre utilis\xE9es que pour des calculs de dimensions et non pas pour des calculs sur des nombres pris en tant qu'entit\xE9s math\xE9matiques\xA7*\decdiv[|)].
+
+\begin{exercice}
+\xC9crire une macro \xA7\convertunit[|(] de syntaxe
+
+\centrecode-\convertunit{<dimension>}{<unit\xE9>}-
+
+qui convertit la \verb|<dimension>| dans l'\verb|<unit\xE9>| sp\xE9cifi\xE9e par les deux caract\xE8res caract\xE9risant chaque unit\xE9, et d'afficher le r\xE9sultat sans unit\xE9. La macro devra \xEAtre purement d\xE9veloppable.
+
+\solution
+Nous allons proc\xE9der comme nous l'avons fait avec la macro \xA7\decdiv : nous allons mettre \idx\numexpr \xE0 contribution pour transformer en \idx{entier contraint} toutes les dimensions et multiplier la \verb|<dimension>| par \verb|1pt| et diviser le tout par
+ \verb|1<unit\xE9>| :
+
+\showcode|\def\convertunit#1#2{%\xA4\xA7*\dimtodec\xA4
+	\dimtodec
+	\dimexpr
+		\numexpr
+			\dimexpr #1 \relax * 65536 / \dimexpr 1#2 \relax
+		\relax
+		sp
+	\relax
+}
+
+a) \convertunit{15cm}{mm}\qquad
+b) \convertunit{9,14in}{cm}\qquad
+c) \convertunit{100000sp}{mm}\qquad
+d) \convertunit{160.5pt}{cm}\qquad
+e) \edef\foo{\convertunit{2,5cm}{cc}}\meaning\foo|
+\xA7*\convertunit[|)]\end{exercice}\idx*[|)]{dimension fixe}
+
+\section{Les dimensions \xE9tirables ou ressorts}\idx*[|(]{registre!ressort}\idx*[|(]{dimension \xE9tirable (ressort)}
+\subsection{\Qu'est-ce qu'un ressort ?}
+Int\xE9ressons-nous maintenant aux ressorts qui ont vocation \xE0 remplir des zones susceptibles d'avoir des tailles variables (souvent pour des raisons typographiques).
+
+\begin{regle}
+Un ressort est une dimension assortie de composantes \xE9tirables optionnelles (\xE9ventuellement infinies) de sorte qu'il peut, selon le contexte et sa d\xE9finition, se comprimer ou s'\xE9tirer. \TeX{} offre 256 registres de ressorts et ce nombre monte \xE0 \numprint{32768} avec \idx\eTeX. La primitive \idx\skip suivie d'un \verb|<nombre>| permet d'acc\xE9der \xE0 un registre sp\xE9cifique par son num\xE9ro.
+
+Plain-\TeX{} fournit la macro \idx\newskip\verb|\<macro>| qui met \xE0 profit la primitive \idx\skipdef selon cette syntaxe
+
+\centrecode-\skipdef\<macro>=<nombre>-
+
+pour rendre cette \verb|\<macro>| \xE9quivalente \xE0 \idx\skip\verb|<nombre>|, o\xF9 le \verb|<nombre>| est celui du prochain registre libre. D\xE8s lors, un \verb|<registre de ressort>|\idx*{registre!ressort} est soit \idx\skip suivi d'un num\xE9ro, soit une \verb|\<macro>| pr\xE9alablement d\xE9finie par \idx\newskip.
+
+Pour assigner un ressort \xE0 un \verb|<registre de ressort>|, il faut \xE9crire :
+
+\centrecode-<registre de ressort>= <ressort>-
+
+\noindent o\xF9 le signe \xAB\verb|=|\xBB et l'espace qui le suit sont optionnels. Pour lire le \verb|<ressort>|, le d\xE9veloppement maximal se met en marche. Un \verb|<ressort>| est une \verb|<dimension>| \xE9ventuellement suivie d'une composante d'\xE9tirement optionnelle de la forme \xAB\verb|plus <\xE9tirement>|\xBB puis d'une composante de compression optionnelle de la forme \xAB\verb|minus <\xE9tirement>|\xBB.
+
+Si elles sont pr\xE9sentes toutes les deux, ces deux composantes optionnelles doivent \emph{n\xE9cessairement} \xEAtre d\xE9clar\xE9es dans cet ordre. Si elles ne sont pas sp\xE9cifi\xE9es, les composantes \xE9tirables valent \verb|0pt| par d\xE9faut.
+
+Un \verb|<\xE9tirement>| est :\label{dimension.ressort}\idx*{registre!ressort!\xE9tirement}
+\begin{itemize}
+	\item soit une composante fixe qui est une \verb|<dimension>| comme \xAB\verb|1.5pt|\xBB ou \xAB\verb|0.25cm|\xBB;
+	\item soit une composante infinie qui prend la forme d'un coefficient d'infini suivi de \xAB\verb|fil|\xBB, \xAB\verb|fill|\xBB ou \xAB\verb|filll|\xBB, o\xF9 ces 3 mots-cl\xE9 repr\xE9sentent des infinis de \emph{forces} diff\xE9rentes : \xAB\verb-filll-\xBB est infiniment plus grand que \xAB\verb|fill|\xBB, quels que soient les coefficients qui les pr\xE9c\xE8dent et de la m\xEAme fa\xE7on, \xAB\verb|fill|\xBB est infiniment plus grand que \xAB\verb|fil|\xBB.
+	
+	Le coefficient d'infini est un d\xE9cimal sign\xE9 dont la valeur absolue peut prendre toutes les valeurs entre 0 et \verb|16383.99999|.
+\end{itemize}
+\end{regle}\idx*[|(]{registre!ressort!\xE9tirement}
+
+\xC0 la mani\xE8re de \idx\dimexpr qui fait des calculs sur les dimensions, la primitive \idx\glueexpr effectue des calculs sur les ressorts :
+
+\showcode|\the\glueexpr 5pt plus 2pt minus 1.5pt + 7pt plus0.5pt minus 3pt\relax \par\xA4\idx*\glueexpr\idx*\the\xA4
+\the\glueexpr 25pt plus2fil + 35pt plus 0.1fill\relax|
+\grandsaut
+
+Envisageons maintenant quelques exemples pour mieux comprendre comment les ressorts fonctionnent et quelles sont leurs \xAB forces \xBB relatives.
+
+Int\xE9ressons-nous tout d'abord aux composantes d'\xE9tirement finies. Le ressort \xAB\texttt{10pt plus1.5pt minus 2.5pt}\xBB a une longueur naturelle de \numprint[pt]{10} mais peut s'allonger jusqu'\xE0 \numprint[pt]{11.5} et se comprimer jusqu'\xE0 \numprint[pt]{7.5}. De la m\xEAme fa\xE7on, le ressort \xAB\texttt{0pt minus5pt}\xBB a une longueur naturelle nulle, mais peut se comprimer jusqu'\xE0 une longueur n\xE9gative de \numprint[pt]{-5}.
+
+Venons-en aux composantes d'\xE9tirement infinies. Supposons qu' un ressort $R_1$ soit \xE9gal \xE0 \xAB\texttt{1.5cm plus2fill}\xBB. Il a une longueur naturelle de \numprint[cm]{1.5} et peut s'allonger autant que n\xE9cessaire comme le sp\xE9cifie sa composante \xE9tirable. Si un autre ressort $R_2$ est d\xE9fini par \xAB\texttt{2.5cm plus3fill}\xBB et si nous demandons \xE0 ces deux ressorts de remplir un espace de \numprint[cm]{10}, la longueur \xE0 combler est de \numprint[cm]{6} puisque la somme des deux longueurs naturelles vaut \numprint[cm]{4}. Le ressort $R_1$ s'allongera de 2/5 la longueur \xE0 combler et $R_2$ de 3/5 de cette longueur, comme le sp\xE9cifient les coefficients d'infini. $R_1$ mesurera  $1.5+6\times2/5=\numprint[cm]{3.9}$ alors que $R_2$ mesurera $2.5+6\times3/5=\numprint[cm]{6.1}$. En voici l'illustration ci-dessous o\xF9 les dimensions naturelles sont en traits pleins et les \xE9tirements en pointill\xE9s. Si aucune op\xE9ration dans l'impression de ce livre n'a provoqu\xE9 d'alt\xE9ration d'\xE9chelle, les dimensions donn\xE9es ci-dessus doivent exactement se retrouver dans ce sch\xE9ma :
+
+\begingroup
+\medbreak
+\ttfamily
+\small
+\hfill
+\leavevmode\lower5pt\hbox{\hbox to1.5cm{\hss 1.5cm\kern2pt}\hbox to2.4cm{\kern2pt plus 2fill\hss}\hbox to2.5cm{\hss2.5cm\kern2pt}\hbox to 3.6cm{\kern2pt plus 3fill\hss}}\hfill\null
+
+\hfill\vrule width0.4pt height 1ex depth 0pt
+\vrule width1.5cm height0.4pt depth 0pt
+\vrule width0.2pt height 1ex depth 0pt
+\hbox to2.4cm{\xleaders\hbox{\vrule width2pt height.4pt\kern1pt }\hfill}%
+\vrule width0.4pt height 1ex depth 0pt
+\vrule width2.5cm height0.4pt depth 0pt
+\vrule width0.4pt height 1ex depth 0pt
+\hbox to3.6cm{\xleaders\hbox{\vrule width2pt height.4pt\kern1pt }\hfill}%
+\vrule width0.4pt height 1ex depth 0pt \hfill\null
+\medbreak\endgroup
+
+Enfin, si un ressort $R_3$ \xE9gal \xE0 \xAB\texttt{3cm plus 20fil}\xBB et un ressort $R_4$ \xE9gal \xE0 \xAB\texttt{2cm plus 0.1fill}\xBB doivent combler un espace de \numprint[cm]{20}, seul $R_4$ s'allongera pour mesurer \numprint[cm]{17} car son infini \xAB\verb|fill|\xBB est infiniment plus grand que \xAB\verb|fil|\xBB.\idx*[|)]{registre!ressort!\xE9tirement}
+
+\subsection{Ins\xE9rer des espaces de dimensions choisies}
+\subsubsection{Insertion d'espaces ins\xE9cables}
+\begin{regle}
+Pour ins\xE9rer une espace ins\xE9cable, on utilise la primitive \idx\kern suivie d'une \verb|<dimension>| qui sera celle de l'espace ins\xE9r\xE9e.
+
+L'espace sera ins\xE9r\xE9e dans le mode en cours : elle sera horizontale si \TeX{} est en mode horizontal\idx*{mode!horizontal} \xE0 ce moment-l\xE0 et sera verticale s'il est en mode vertical\idx*{mode!vertical}.
+
+L'espace ainsi cr\xE9\xE9 est \emph{ins\xE9cable} car aucune coupure de ligne ou de page ne pourra s'y faire.
+\end{regle}
+
+\showcode/foo% les caract\xE8res font entrer TeX en mode horizontal\xA4\idx*{mode!horizontal}\xA4
+\kern0.5cm % espace ins\xE9r\xE9e en mode horizontal\xA4\idx*{mode!horizontal}\xA4
+bar\par% \par fait passer en mode vertical\xA4\idx*{mode!vertical}\xA4
+\kern0.5cm % espace ins\xE9r\xE9e en mode vertical
+boo/
+
+L'espace verticale entre la fronti\xE8re basse de \xABbar\xBB et la fronti\xE8re haute de \xABboo\xBB n'est pas \verb|0.5cm|, car le ressort d'interligne vient s'ajouter \xE0 la dimension ins\xE9cable ins\xE9r\xE9e par \idx\kern.
+
+\subsubsection{Insertion d'espaces s\xE9cables}
+\xC0 la diff\xE9rence des espaces ins\xE9cables, un espace est dit \xAB \emph{s\xE9cable} \xBB s'il peut c\xE9der sa place \xE0 une coupure (de ligne ou de page). Le verbe \xAB c\xE9der \xBB sugg\xE8re que si une coupure est faite, l'espace est retir\xE9 de la liste en cours et est remplac\xE9 par une coupure.
+
+\begin{regle}
+La primitive \idx\hskip, suivie d'un \verb|<ressort>| ins\xE8re une espace (dont les dimensions sont celles permises par le ressort\idx*{registre!ressort}) dans la liste horizontale en cours. La primitive \idx\vskip en est le pendant pour le mode vertical\idx*{mode!vertical}.
+
+Si \TeX{} rencontre une de ces deux primitives et ne se trouve pas dans le mode qu'elles exigent, alors le mode courant se termine et \TeX{} passe dans le mode requis.
+
+Les espaces ainsi ins\xE9r\xE9es sont s\xE9cables, c'est-\xE0-dire susceptibles d'\xEAtre remplac\xE9es par des coupures de ligne ou de pages. De plus, elles sont ignor\xE9es lorsqu'elles se trouvent imm\xE9diatement avant la fin du \idx[!espaces ignor\xE9s]{paragraphe} pour \idx\hskip ou de la fin de la page pour \idx\vskip.
+\end{regle}
+
+Il est utile de savoir qu'en mode horizontal\idx*{mode!horizontal}, le token espace (de catcode 10\idx*{catcode!10 (espace)} et de code de caract\xE8re 32) se comporte comme un ressort\idx*{registre!ressort} : il a une dimension naturelle et peut, dans une certaine mesure, se comprimer ou se dilater (lire page~\pageref{espace.dimensions.fonte}).
+\grandsaut
+
+Certaines primitives sont en r\xE9alit\xE9 des ressort\idx*{registre!ressort}s. Il est important de distinguer deux types de \xAB ressorts-primitives \xBB :
+
+\begin{itemize}
+	\item ceux qui sont \emph{modifiables} et qui se comportent comme une macro d\xE9finie avec \idx\newskip. Ces ressorts-primitives sont susceptibles de recevoir un \verb|<ressort>| par assignation. La plupart de ces ressorts-primitives concernent des r\xE9glages typographiques;
+	\item ceux, non modifiables, dont la valeur est pr\xE9d\xE9finie et invariable.
+\end{itemize}
+
+Le tableau ci-dessous, sans \xEAtre exhaustif, liste quelques ressorts utilis\xE9s par \TeX{}, qu'ils soient de simples macros d\xE9finies avec \idx\newskip (partie du haut), des ressorts-primitives modifiables (\xE9crits en gras dans la partie du milieu) ou ressorts-primitives non modifiables (pr\xE9c\xE9d\xE9s d'une \xAB$*$\xBB dans la partie basse).
+
+Dans chaque cat\xE9gorie, la valeur par d\xE9faut assign\xE9e par plain-\TeX{} ou le comportement (pour les ressorts-primitives non modifiables) est donn\xE9 dans la colonne \xAB D\xE9finition \xBB  tandis que le mode dans lequel le \idx*{registre!ressort}ressort est utilis\xE9 est donn\xE9 dans la colonne de droite.\medbreak
+
+\begingroup
+	\small
+	\LTpre2\parskip \LTpost\parskip\label{tableau.ressort}%
+	\begin{longtable}{>\ttfamily r@{}c@{}>\ttfamily l@{\kern1em}c}\hline
+		Nom && D\xE9finition & Mode\\\hline\endhead
+		\idx\hideskip&${}={}$&-1000pt plus 1fill& h\\
+		\idx\centering&${}={}$&0pt plus 1000pt minus 1000pt& h\\
+		\idx\z at skip&${}={}$&0pt plus0pt minus0pt& h ou v\\
+		\idx\smallskipamount&${}={}$&3pt plus 1pt minus 1pt&v\\
+		\idx\medskipamount&${}={}$&6pt plus 2pt minus 2pt&v\\
+		\idx\bigskipamount&${}={}$&12pt plus 4pt minus 4pt&v\\\hline
+		\bfseries\idx\baselineskip&${}={}$&12pt&v\\
+		\bfseries\idx\lineskip&${}={}$&1pt&v\\
+		\bfseries\idx\leftskip&${}={}$&0pt&h\\
+		\bfseries\idx\rightskip&${}={}$&0pt&h\\
+		\bfseries\idx\parskip&${}={}$&0pt plus 1pt& v\\
+		\bfseries\idx\parfillskip&${}={}$&0pt plus 1fil& h\\\hline
+		\llap{${}^*$}\idx\hfil&${}\equiv{}$&\string\hskip{} 0pt plus 1fil&h\\
+		\llap{${}^*$}\idx\hfilneg&${}\equiv{}$&\string\hskip{} 0pt plus -1fil&h\\
+		\llap{${}^*$}\idx\hfill&${}\equiv{}$&\string\hskip{} 0pt plus 1fill&h\\
+		\llap{${}^*$}\idx\vfil&${}\equiv{}$&\string\vskip{} 0pt plus 1fil&v\\
+		\llap{${}^*$}\idx\vfilneg&${}\equiv{}$&\string\vskip{} 0pt plus -1fil&v\\
+		\llap{${}^*$}\idx\vfill&${}\equiv{}$&\string\vskip{} 0pt plus 1fill&v\\
+		\llap{${}^*$}\idx\hss&${}\equiv{}$&\string\hskip{} 0pt plus1fil minus1fil&h\\
+		\llap{${}^*$}\idx\vss&${}\equiv{}$&\string\vskip{} 0pt plus1fil minus1fil&v\\\hline
+	\end{longtable}
+\endgroup
+
+\subsection{Les ressorts typographiques}
+Int\xE9ressons-nous aux ressorts-primitives \xE9crits en gras dans le tableau pr\xE9c\xE9dent. Ces ressorts sont examin\xE9s lorsque le paragraphe est compos\xE9\idx*{paragraphe!composition}, c'est-\xE0-dire lorsque \idx\par est ex\xE9cut\xE9. Il est donc inutile de modifier plusieurs fois ces ressorts dans le m\xEAme paragraphe puisque seule la derni\xE8re valeur sera prise en compte.
+
+Cela implique en particulier que si un paragraphe\idx*{paragraphe!composition} est compos\xE9 dans un groupe (semi-simple ou non) dans lequel certains de ces ressorts sont modifi\xE9s, il est n\xE9cessaire de composer le paragraphe \emph{avant} de fermer le groupe. En \xE9crivant \idx\par avant la fin du groupe, on s'assure que les valeurs des ressorts, modifi\xE9es dans le groupe, seront bien prises en compte. En revanche, rejeter le \idx\par hors du groupe constitue une erreur, car les valeurs, restaur\xE9es trop t\xF4t \xE0 ce qu'elles \xE9taient avant les modifications, rendent inutiles ces modifications internes au groupe.
+
+\subsubsection{Ressort d'interligne}\label{ressort.interligne}\idx*[|(]{paragraphe!espace interligne}
+Les boites contenant deux lignes cons\xE9cutives d'un paragraphe ne sont g\xE9n\xE9ralement pas jointives. Le sch\xE9ma ci-dessous illustre la situation : la distance entre les lignes de base des deux lignes cons\xE9cutives est not\xE9e $\Delta$ tandis que la distance entre les fronti\xE8res des deux boites est not\xE9e $\delta$.
+
+\begin{centrage}
+	\begin{tikzpicture}[inner sep=0pt,outer sep=0pt,minimum size=0pt,baseline,line width=0.4pt]
+		\node[anchor=base west,draw,inner sep=-0.2pt]at(0,0)(boiteA){\vrule width0pt height.6cm depth.3cm \vrule height0pt width 3cm depth0pt };\draw[fill,black,overlay](boiteA.base west)circle(1pt);%
+		\draw[gray,overlay]([xshift=-1cm]boiteA.base west)--([xshift=1cm]boiteA.base east)node[pos=1,anchor=south east,black,outer sep=1pt]{\tiny ligne de}node[pos=1,anchor=north east,black,outer sep=1pt]{\tiny base};
+		\node[anchor=base west,draw,inner sep=-0.1pt]at(0,-1.2)(boiteB){\vrule width0pt height.5cm depth.2cm \vrule height0pt width 4cm depth0pt };
+		\draw[fill,black,overlay](boiteB.base west)circle(1pt);%
+		\draw[gray,overlay]([xshift=-1cm]boiteB.base west)--([xshift=1cm]boiteB.base east)node[pos=1,anchor=south east,black,outer sep=1pt]{\tiny ligne de}node[pos=1,anchor=north east,black,outer sep=1pt]{\tiny base};
+		\draw[stealth-stealth]([xshift=-1.2cm]boiteA.base west)--([xshift=-1.2cm]boiteB.base west)node[pos=.5]{\footnotesize\llap{$\Delta$}\kern.75em };
+		\draw[stealth-stealth]([xshift=-.2cm]boiteA.south west)--([xshift=-.2cm]boiteB.north west)node[pos=.5]{\footnotesize\llap{$\delta$}\kern.75em };
+		\draw[stealth-stealth]([xshift=-.6cm]boiteA.south west)--([xshift=-.6cm]boiteA.base west)node[pos=.5]{\footnotesize\llap{$p$}\kern.75em };
+		\draw[stealth-stealth]([xshift=-.6cm]boiteB.north west)--([xshift=-.6cm]boiteB.base west)node[pos=.5]{\footnotesize\llap{$h$}\kern.75em };
+	\end{tikzpicture}
+\end{centrage}
+
+Plus g\xE9n\xE9ralement, si des boites sont empil\xE9es les unes au-dessous des autres en mode vertical, un ressort-primitive vertical \xAB\idx\baselineskip\xBB est ins\xE9r\xE9 entre elles. Ce ressort-primitive, appel\xE9 \xAB \idx{ressort d'interligne} \xBB, mesure l'espace ins\xE9r\xE9e entre les \emph{lignes de base} de ces boites.
+
+Si la g\xE9om\xE9trie des boites (pr\xE9cis\xE9ment la quantit\xE9 $p+h$) fait que $\delta$ devient strictement inf\xE9rieur \xE0 une certaine limite stock\xE9e dans la dimension-primitive \idx\lineskiplimit, alors les deux boites sont empil\xE9es verticalement de telle sorte que $\delta$ soit \xE9gal au ressort-primitive \idx\lineskip. Math\xE9matiquement, si
+
+\[\Delta-(p+h)<\text{\ttfamily\char`\\lineskiplimit}\]\idx*\lineskiplimit
+\noindent alors l'insertion de \idx\baselineskip entre les lignes de base est abandonn\xE9e et le ressort-primitive \idx\lineskip est ins\xE9r\xE9 \emph{entre les fronti\xE8res des boites}.
+
+Plain-\TeX{} effectue les initialisations suivantes :
+
+\centrecode-\baselineskip=12pt    \lineskiplimit=0pt    \lineskip=1pt-
+
+La macro \idx\nointerlineskip doit \xEAtre appel\xE9e en mode vertical et annule l'insertion du prochain \idx{ressort d'interligne} entre deux boites. Cette macro est \xE0 \xAB un seul coup \xBB et devra \xEAtre appel\xE9e \xE0 nouveau si plus tard, on souhaite annuler l'insertion du ressort d'interligne entre deux autres boites.
+
+\showcode/Une premi\xE8re ligne\par
+\nointerlineskip% n'ins\xE8re pas de ressort d'interligne ici\xA4\idx*\nointerlineskip\xA4
+Un second paragraphe constitu\xE9 de plusieurs lignes.
+Un second paragraphe constitu\xE9 de plusieurs lignes.
+Un second paragraphe constitu\xE9 de plusieurs lignes.
+\par% le ressort d'interligne sera ins\xE9r\xE9 ici
+Une derni\xE8re ligne/
+
+La macro \idx\offinterlineskip, d\xE9sactive durablement l'insertion du ressort d'interligne. Il est prudent de l'utiliser dans un groupe afin d'en limiter la port\xE9e.
+
+\showcode/\begingroup
+\offinterlineskip\xA4\idx*\offinterlineskip\xA4
+La macro \litterate-\offinterlineskip-, en modifiant de fa\xE7on appropri\xE9e les trois\xA4\idx*\offinterlineskip\xA7*\litterate\xA4
+primitives \litterate-\baselineskip-, \litterate-\lineskip- et\xA4\idx*\offinterlineskip\xA4
+\litterate-\lineskiplimit-, rend les boites cons\xE9cutives jointives.\xA4\idx*\baselineskip\idx*\lineskip\idx*\lineskiplimit\xA4
+
+On peut constater dans ces deux paragraphes o\xF9 \litterate-\offinterlineskip- a \xE9t\xE9\xA4\idx*\offinterlineskip\xA7*\litterate\xA4
+appel\xE9e, que les lignes sont plac\xE9es verticalement au plus pr\xE8s les unes des autres ce
+qui rend la lecture tr\xE8s p\xE9nible et d\xE9montre que le ressort d'interligne est une\xA4\idx*{ressort d'interligne}\xA4
+n\xE9cessit\xE9 typographique !\par
+\endgroup
+D\xE9sactiver le ressort d'interligne ne se justifie que lorsque l'on doit composer\xA4\idx*{ressort d'interligne}\xA4
+des boites contenant autre chose que du texte, sauf \xE0 vouloir des effets
+typographiques sp\xE9ciaux./
+
+Les deux cas les plus courants o\xF9 la quantit\xE9 $p+h$ est \xE9lev\xE9e sont :
+
+\begin{enumerate}
+	\item la boite du haut est tr\xE8s profonde et $p$ est grand (boite de type \idx\vtop);
+	\item la boite du bas est tr\xE8s haute et $h$ est grand (boite de type \idx\vbox).
+\end{enumerate}
+
+En voici l'illustration o\xF9 nous allons construire une boite du haut profonde et o\xF9 nous augmentons \idx\baselineskip afin de mieux visualiser le probl\xE8me :
+
+\showcode/\baselineskip=12pt
+d\xE9but \vtop{\hbox{ligne du haut ligne du haut ligne du haut}\xA4\idx*\vtop\xA4
+\hbox{ligne du bas ligne du bas ligne du bas}
+}
+\par
+Et la suite du texte suite du texte suite du texte/
+
+On constate que l'espace vertical entre la \xAB ligne du bas \xBB de la \idx\vtop et la ligne suivante n'est pas \idx\baselineskip. En effet, \idx\lineskip a \xE9t\xE9 ins\xE9r\xE9 entre la fronti\xE8re de la \idx\vtop et la premi\xE8re ligne du paragraphe qui suit. Pour r\xE9tablir un espacement correct, il faut mentir \xE0 \TeX{} sur la profondeur de la boite pr\xE9c\xE9dente. En mode vertical\idx*{mode!vertical}, la primitive \idx\prevdepth (qui mesure la longueur $p$ du sch\xE9ma), ayant le type d'une dimension, contient la profondeur de la pr\xE9c\xE9dente boite plac\xE9e dans la liste verticale. Apr\xE8s \xEAtre sorti de la \idx\vtop, cette valeur est \xE9lev\xE9e du fait de la profondeur de la boite. L'astuce consiste \xE0 sauvegarder $p$ dans une macro \xE0 la fin de la \idx\vtop de telle sorte que cette macro contienne la profondeur \emph{de la derni\xE8re ligne} de la boite. Comme on ne peut acc\xE9der \xE0 \idx\prevdepth qu'en mode vertical\idx*{mode!vertical}, il suffit donc apr\xE8s le \idx\par d'assigner \xE0 \idx\prevdepth la valeur sauvegard\xE9e.
+
+\showcode/\baselineskip=12pt
+d\xE9but \vtop{\hbox{ligne du haut ligne du haut ligne du haut}\xA4\idx*\vtop\xA4
+\hbox{ligne du bas ligne du bas ligne du bas}
+\xdef\sprevdepth{\the\prevdepth}% sauvegarde la valeur de \prevdepth\xA4\idx*\xdef\xA4
+}
+\par\prevdepth=\sprevdepth\relax% ment sur la boite pr\xE9c\xE9dente\xA4\idx*\prevdepth\xA4
+Et la suite du texte suite du texte suite du texte/\idx*[|)]{paragraphe!espace interligne}
+
+\subsubsection{Les ressorts de paragraphe}\idx*[|(]{paragraphe!ressorts de paragraphe}
+Avant de commencer un paragraphe, \TeX{} ajoute \xE0 la liste verticale l'espace mesur\xE9 par le ressort-primitive \idx\parskip (il n'est pas ajout\xE9 si la liste verticale est vide, c'est-\xE0-dire au d\xE9but d'une page ou d'une boite verticale). Ce ressort vient donc s'additionner au \idx{ressort d'interligne} vu pr\xE9c\xE9demment. Plain-\TeX{} proc\xE8de \xE0 l'assignation suivante :
+
+\centrecode-\parskip= 0pt plus 1pt-
+
+Apr\xE8s la fin de la derni\xE8re ligne d'un paragraphe, \TeX{} ins\xE8re horizontalement le ressort-primitive \idx\parfillskip. Plain-\TeX{} demande \xE0 ce que
+
+\centrecode-\parfillskip= 0pt plus1fil-
+
+\begingroup
+\hbadness=10000 % pour \xE9viter une avertissement de boite insuffisemment remplie
+\parfillskip=0pt\relax
+\noindent ce qui signifie qu'un ressort d'\xE9tirement infini est ins\xE9r\xE9 en fin de paragraphe. L'effet d'un tel ressort est de \xAB pousser \xBB le texte de la derni\xE8re ligne de fa\xE7on \xE0 ce qu'il ne se justifie pas. On peut bien s\xFBr modifier ce ressort pour obtenir des effets typographiques comme dans ce paragraphe o\xF9 ce ressort a \xE9t\xE9 rendu nul sans \xE9tirement afin que la derni\xE8re ligne soit justifi\xE9e. Cet effet doit \xEAtre utilis\xE9 avec parcimonie, car les espaces intermots de cette derni\xE8re ligne, beaucoup trop larges ici, d\xE9montrent que cet effet peut parfois \xEAtre tr\xE8s inesth\xE9tique.
+\par
+\endgroup
+\medbreak
+
+Afin de bien voir la modification de la composition du paragraphe que cela entraine, voici le paragraphe pr\xE9c\xE9dent avec un ressort de fin de paragraphe ayant sa valeur par d\xE9faut :\smallbreak
+
+\noindent ce qui signifie qu'un ressort d'\xE9tirement infini est ins\xE9r\xE9 en fin de paragraphe. L'effet d'un tel ressort est de \xAB pousser \xBB le texte de la derni\xE8re ligne de fa\xE7on \xE0 ce qu'il ne se justifie pas. On peut bien s\xFBr modifier ce ressort pour obtenir des effets typographiques comme dans ce paragraphe o\xF9 ce ressort a \xE9t\xE9 rendu nul sans \xE9tirement afin que la derni\xE8re ligne soit justifi\xE9e. Cet effet doit \xEAtre utilis\xE9 avec parcimonie, car les espaces intermots de cette derni\xE8re ligne, beaucoup trop larges ici, d\xE9montrent que cet effet peut parfois \xEAtre tr\xE8s inesth\xE9tique.
+
+\subsubsection{Ressorts d'extr\xE9mit\xE9s de ligne}
+Les ressorts \idx\leftskip et \idx\rightskip sont ins\xE9r\xE9s avant et apr\xE8s le contenu de chaque ligne (\idx\rightskip est ajout\xE9 apr\xE8s \idx\parfillskip \xE0 la derni\xE8re ligne du paragraphe). Lorsqu'ils sont \xE9gaux \xE0 \verb|0pt| comme c'est le cas par d\xE9faut, le d\xE9but et la fin de la ligne co\xEFncident avec les limites de la zone de texte et le texte est dit \xAB justifi\xE9 \xBB : ce sont les espaces entre les mots qui s'ajustent pour permettre cet effet typographique. La modification de ces ressorts d'extr\xE9mit\xE9s de ligne permet des compositions qui contrarient cette justification.
+
+Ainsi, donner une composante infinie \xE0 ces ressorts revient \xE0 les faire \xAB pousser \xBB avec une force infinie de telle sorte que les espaces entre les mots seront contraints \xE0 prendre leur dimension \emph{naturelle} ce qui cassera la justification. Il est cependant plus judicieux de donner comme \xE9tirement une composante \emph{finie} de telle sorte que celle-ci ne contraigne pas les espaces intermots. Il est utile de savoir qu'une composante \emph{infinie} des ressorts d'extr\xE9mit\xE9 de ligne d\xE9courage \TeX{} d'effectuer une seconde passe lors de la composition du paragraphe. Seule la premi\xE8re passe est donc faite et les coupures de mots, envisag\xE9es \xE0 la seconde passe, ne seront donc jamais faites (lire page~\pageref{provoquer.toutes.les.coupures}).
+
+On voit que les ressorts d'extr\xE9mit\xE9s de ligne entretiennent un rapport avec les espaces intermots dont il est temps de parler. Chaque police poss\xE8de des registres internes d\xE9finissant la largeur naturelle de l'espace intermot, son possible \xE9tirement et sa possible compression (lire page~\pageref{espace.dimensions.fonte}). Le ressort-primitive \idx\spaceskip permet, lorsqu'il re\xE7oit une assignation, d'\xE9craser localement le contenu des registres de la police concernant les dimensions de l'espace intermot. Il est donc possible de supprimer la composante \xE9tirable de l'espace intermot afin que des espaces intermots trop longs et disgracieux soient \xE9vit\xE9s dans une composition non justifi\xE9e.
+\grandsaut
+
+Les effets typographiques les plus courants obtenus \xE0 l'aide des ressorts d'extr\xE9mit\xE9 de ligne sont :
+
+\begin{itemize}
+	\item composition au fer \xE0 gauche en donnant une composante \xE9tirable finie (par exemple 2 ou 3 \verb|em|) \xE0 \idx\rightskip et en laissant \idx\leftskip nul;
+	\item composition au fer \xE0 droite en inversant les r\xF4les des deux ressorts dans la man\oe uvre d\xE9crite au point pr\xE9c\xE9dent;
+	\item centrage du contenu des lignes en donnant la \emph{m\xEAme} composante \xE9tirable aux deux ressorts. Cette composante doit ici \xEAtre assez grande pour permettre le centrage de lignes tr\xE8s courtes. Le choix de \verb|1000pt| est fait par plain-\TeX{} tandis que \LaTeX{} fait le choix de \texttt{0pt plus 1fil} pour sa macro \idx\centering. On peut \xE9galement choisir \verb|0.5|\idx\hsize o\xF9 \idx\hsize est la dimension-primitive qui contient la largeur de composition. Enfin, pour que la derni\xE8re ligne soit centr\xE9e, il faut \xE9galement annuler \idx\parfillskip qui sinon, deviendrait pr\xE9pond\xE9rant par rapport \xE0 \idx\leftskip et \idx\rightskip.
+\end{itemize}
+
+Voici un exemple de m\xE9thode pour centrer deux paragraphes\idx*{paragraphe!centrage} entiers :
+
+\showcode/\def\dummytext{Voici un texte qui ne rev\xEAt aucune importance
+	et dont le seul but est de meubler artificiellement un paragraphe. }
+\begingroup% \xE0 l'int\xE9rieur d'un groupe,\xA4\idx*\begingroup\xA4
+	\leftskip=0pt plus 0.5\hsize\relax\xA4\idx*\leftskip\idx*\hsize\xA4
+	\rightskip=\leftskip\relax % modifier les ressort d'extr\xE9mit\xE9s\xA4\idx*\rightskip\idx*\leftskip\xA4
+	\spaceskip=0.3em plus 0.05em\relax% dimension de l'espace intermot\xA4\idx*\spaceskip\xA4
+	\parfillskip=0pt \relax% annuler le ressort de fin de paragraphe\xA4\idx*\parfillskip\xA4
+	\dummytext\dummytext\dummytext% corps du paragraphe
+	\par% compose la paragraphe courant
+	Juste une phrase%
+	\par% compose la paragraphe courant
+\endgroup% avant de sortir du groupe\xA4\idx*\endgroup\xA4/
+
+En suivant cette m\xE9thode, il est facile de construire une macro \xA7\narrowtext qui compose le paragraphe pr\xE9c\xE9dent et qui diminue d\xE9sormais la largeur de composition de 20\% de la largeur totale\idx*{paragraphe!diminuer la largeur}, sachant que cette largeur est contenue dans la dimension-primitive \idx\hsize. Le \xAB bloc \xBB de composition ainsi constitu\xE9 devra \xEAtre centr\xE9 par rapport aux fronti\xE8res de la zone de texte. Il faut pour cela augmenter (via la primitive \idx\advance) chacun des deux ressorts d'extr\xE9mit\xE9s de ligne de \verb|.1\hsize|. La macro \verb|\endnarrowtext| signera la fin de la composition en largeur diminu\xE9e; elle composera le paragraphe en cours avec \idx\par et fermera le groupe semi-simple ouvert par \xA7\narrowtext.
+
+\showcode/\def\narrowtext{%\xA4\xA7*\narrowtext\xA4
+	\par
+	\begingroup
+		\advance\leftskip 0.1\hsize\xA4\idx*\advance\idx*\leftskip\xA4
+		\advance\rightskip 0.1\hsize\xA4\idx*\advance\idx*\rightskip\xA4
+}
+\def\endnarrowtext{\par\endgroup}
+\def\dummytext{Ceci est un texte sans
+ importance destin\xE9 \xE0 meubler un paragraphe. }
+
+\dummytext\dummytext\dummytext
+\narrowtext
+	\dummytext\dummytext\dummytext
+ \narrowtext
+		\dummytext\dummytext\dummytext
+ \endnarrowtext
+	\dummytext\dummytext\dummytext
+\endnarrowtext/
+
+Comme aucune des macros \xA7\narrowtext ou \verb|\endnarrowtext| n'admet d'argument, il n'y a aucun risque de mettre entre elles un contenu tr\xE8s long qui aurait pu inutilement surcharger la m\xE9moire de \TeX{} s'il avait \xE9t\xE9 maladroitement incorpor\xE9 dans un argument. L'autre avantage est que la lecture d'arguments est assortie du gel des catcodes qui n'existe pas ici.\idx*[|)]{paragraphe!ressorts de paragraphe}
+
+\subsection{Ressorts pr\xE9d\xE9finis}
+Les ressorts-primitives modifiables --~ceux qui \xE9taient pr\xE9c\xE9d\xE9s d'une \xE9toile dans le tableau de la page~\pageref{tableau.ressort}~-- se comportent exactement comme s'ils \xE9taient des macros d\xE9finies avec \idx\newskip. La seule diff\xE9rence est que leur valeur est fig\xE9e. On remarque que \idx\hfil et \idx\vfil sont compens\xE9s (c'est-\xE0-dire annul\xE9s) par \idx\hfilneg et \idx\vfilneg.
+
+Les ressorts \idx\hss et \idx\vss sont eux encore plus curieux puisque, de dimension nulle, ils peuvent s'\xE9tirer ou se comprimer infiniment. Nous verrons leur int\xE9r\xEAt plus loin.
+
+Voici comment nous pouvons utiliser \idx\hfill pour composer au fer \xE0 droite, au fer \xE0 gauche, centrer une ligne ou bien encore, r\xE9guli\xE8rement espacer zones de texte sur une ligne :
+
+\showcode/a) \hfill Composition au fer \xE0 droite\par
+b) Composition au fer \xE0 gauche\hfill\kern0pt\par
+c) \hfill Centrage\hfill\kern0pt\par
+d) Des \hfill mots\hfill r\xE9guli\xE8rement\hfill espac\xE9s/
+
+Comment se justifie la pr\xE9sence de ces \xAB \idx\kern\verb|0pt|\xBB apr\xE8s les \idx\hfill en \idx{fin de ligne} ? Tout vient de la r\xE8gle pr\xE9c\xE9dente qui stipule qu'un ressort qui se situe juste avant la fin d'un paragraphe (autrement dit juste avant \idx\par) est \emph{ignor\xE9}. Ce \verb|\kern0pt| n'a d'autre but que de mettre quelque chose (on appelle cela un n\oe ud) entre le ressort et \idx\par. Bien \xE9videmment, la dimension de ce n\oe ud doit \xEAtre nulle afin que son encombrement ne fausse pas la largeur des \xE9l\xE9ments pris en compte. Au lieu d'\xE9crire \verb|\kern0pt|, il est \xE9galement courant d'employer la macro \idx\null d\xE9finie par plain-\TeX{} dont le texte de remplacement est une boite horizontale vide, c'est-\xE0-dire \idx\hbox\verb|{}|\idx*[|)]{registre!ressort}\idx*[|)]{dimension \xE9tirable (ressort)}\idx*[|)]{dimension}.
+
+\section{Les boites}\label{boites}\idx*[|(]{boite}
+Dans le monde de \TeX{}, presque tout ce qui concerne la composition est li\xE9 aux boites. Les dimensions sont notamment utilis\xE9es pour mesurer les caract\xE9ristiques g\xE9om\xE9triques de ces boites. Les ressorts eux, sont charg\xE9s de remplir des zones dans ces boites.
+
+Avant de commencer, il est important de comprendre qu'une boite re\xE7oit du code source transmis sous la forme d'un argument, mais prend en compte le r\xE9sultat typographique de ce code \emph{une fois qu'il a \xE9t\xE9 compos\xE9}. Les assignations sont mises \xE0 part pour \xEAtre ex\xE9cut\xE9s lorsque la boite est affich\xE9e. Ainsi, mettre quelque chose dans une boite implique donc au pr\xE9alable le travail complet de composition.
+
+\subsection{Fabriquer des boites}
+Si \TeX{}, de par son fonctionnement lors de la composition, fabrique automatiquement des boites pour les placer sur la page, des primitives permettent \xE0 l'utilisateur de fabriquer ses propres boites avec la possibilit\xE9 d'y mettre un contenu arbitraire.
+
+\begin{regle}
+	\relax\TeX{} dispose de trois primitives pour enfermer un mat\xE9riel dans une boite :
+	
+	\begin{itemize}
+		\item \idx\hbox\verb|{<code>}| construit une boite \emph{horizontale} contenant du mat\xE9riel (qui est le r\xE9sultat de la composition du \verb|<code>|) dispos\xE9 en mode horizontal\idx*{mode!horizontal} et compatible avec ce mode;
+		\item \idx\vbox\verb|{<code>}| et \idx\vtop\verb|{<code>}| b\xE2tissent des boites \emph{verticales}, susceptibles donc de recevoir du mat\xE9riel dispos\xE9 en mode vertical\idx*{mode!vertical} et compatible avec ce mode.
+	\end{itemize}
+
+	Dans les trois cas, l'int\xE9rieur d'une boite tient lieu de groupe, c'est-\xE0-dire que les assignations faites dans le \verb|<code>| restent locales \xE0 la boite.
+	
+	Le \verb|<code>| n'est pas lu en une fois comme s'il \xE9tait l'argument d'une macro; il est lu \emph{au fur et \xE0 mesure} que la boite se remplit et donc au fil de cette lecture, des changements de catcode sont permis.
+
+	Une boite ainsi construite peut \xEAtre :
+	
+	\begin{itemize}
+		\item affich\xE9e lorsque \idx\hbox, \idx\vbox ou \idx\vtop sont plac\xE9s dans le flux d'entr\xE9e de \TeX. Dans ce cas, la boite est ajout\xE9e \xE0 la liste en cours selon le mode dans lequel \TeX{} travaille \xE0 ce moment (\idx*{boite!mode}horizontal\idx*{mode!horizontal} ou vertical\idx*{mode!vertical}). Il est important de noter que ni \idx\hbox ni \idx\vbox ou \idx\vtop ne provoquent de changement de mode, m\xEAme si \xE0 l'int\xE9rieur de ces boites, un mode \xABinterne\xBB\idx*{mode!interne} est impos\xE9;
+		\item stock\xE9e dans un registre de boite (voir la section suivante).
+	\end{itemize}
+\end{regle}
+
+Le code ci-dessous d\xE9montre que les boites s'affichent selon le mode en cours :
+
+\showcode/a% le caract\xE8re "a" fait passer en mode horizontal\xA4\idx*{mode!horizontal}\xA4
+\hbox{b}c\hbox{d}% les \hbox sont ajout\xE9es en mode horizontal\xA4\idx*{mode!horizontal}\xA4
+\medbreak
+...\xE0 comparer avec...
+\medbreak
+a \par% \par fait passer en mode vertical\xA4\idx*{mode!vertical}\xA4
+\hbox{b}% \hbox est ajout\xE9e \xE0 la liste verticale
+c% "c" fait passer en mode horizontal\xA4\idx*{mode!horizontal}\xA4
+\hbox{d}% la \hbox est ajout\xE9e en mode horizontal/
+
+Il est important de se souvenir de cette r\xE8gle lorsqu'on construit une macro dont le premier acte est d'afficher une boite construite avec une des trois primitives vues ci-dessus. En effet, on souhaite souvent placer d'autres choses \xE0 droite de cette boite (en mode horizontal donc). Si la macro est appel\xE9e en mode vertical, le placement se fera \emph{en dessous}, et non pas \emph{apr\xE8s} comme attendu. Pour se pr\xE9munir de ce risque, il est \emph{tr\xE8s sage} de mettre un \idx\leavevmode avant la boite pour quitter le mode vertical\idx*{mode!vertical}. Ce faisant, la boite sera compos\xE9e en mode horizontal\idx*{mode!horizontal} et le comportement recherch\xE9 sera obtenu.
+\grandsaut
+
+Les boites construites avec \idx\vbox ou \idx\vtop empilent verticalement des \xE9l\xE9ments. Ces \xE9l\xE9ments sont susceptibles d'\xEAtre mis dans une liste verticale car, \xE0 l'int\xE9rieur de \idx\vbox ou \idx\vtop, on est dans le mode vertical (plus exactement en mode vertical \emph{interne}\idx*{mode!vertical interne}). Ce sont par exemple des paragraphes (qui ont une largeur \xE9gale \xE0 \idx\hsize), des boites form\xE9es avec une des trois primitives, des ressorts verticaux ins\xE9r\xE9s avec \idx\vskip, des r\xE9glures (que nous verrons un peu plus loin), etc.
+
+Autant la largeur d'une \idx\hbox est clairement la largeur du mat\xE9riel que l'on y a mis, autant celle d'une \idx\vbox ou \idx\vtop est moins \xE9vidente; La largeur d'une boite verticale est celle de l'\xE9l\xE9ment empil\xE9 verticalement qui a la plus grande largeur. Mais attention, si on \xE9crit  \xAB\verb|\vbox{foobar}|\xBB ou \xAB\verb|\vtop{foobar}|\xBB, \TeX{} composera un paragraphe pour ce seul mot et mettra cet \xE9l\xE9ment dans la boite. Or, la largeur des paragraphes est \xE9gale \xE0 la dimension-primitive \idx\hsize qui, dans le mode vertical principal, contient la largeur de la zone de texte. L'int\xE9rieur d'une boite jouant le r\xF4le de groupe, on peut certes modifier \idx\hsize dans une boite verticale pour imposer aux paragraphes une largeur choisie. Sans cette man\oe uvre pour modifier \idx\hsize, la largeur de la boite sera la m\xEAme que celles des paragraphes de la page, ce qui est peut-\xEAtre un peu surdimensionn\xE9 pour un paragraphe aussi court que \xABfoobar\xBB ! Au contraire, si l'on \xE9crit \xAB\verb|\vbox{\hbox{foobar}}|\xBB ou \xAB\verb|\vtop{\hbox{foobar}}|\xBB, l'\xE9l\xE9ment qu'est la \idx\hbox sera ins\xE9r\xE9 (en mode vertical\idx*{mode!vertical}) et au final, la boite verticale aura la largeur de cet \xE9l\xE9ment, c'est-\xE0-dire la largeur du mot \xAB foobar \xBB.
+
+\begin{regle}
+Les primitives \idx\vbox et \idx\vtop d\xE9finissent des boites dans lesquelles des \xE9l\xE9ments sont empil\xE9s verticalement.
+
+La diff\xE9rence entre \idx\vbox et \idx\vtop r\xE9side dans le \idx{point de r\xE9f\xE9rence} de la boite finale. Dans les deux cas, les \xE9l\xE9ments sont empil\xE9s verticalement, le premier \xE9tant en haut et le dernier en bas. Avec \idx\vbox, le point de r\xE9f\xE9rence de la boite est le point de r\xE9f\xE9rence du \emph{dernier} \xE9l\xE9ment (celui du bas) alors qu'avec \idx\vtop, son point de r\xE9f\xE9rence est celui du \emph{premier} \xE9l\xE9ment (celui du haut).
+\end{regle}
+
+Le \idx{point de r\xE9f\xE9rence} d'une boite \xE9tant sur la \idx{ligne de base}, on comprend donc que \idx\vbox construit des empilements ayant des \xE9l\xE9ments au-dessus de cette ligne et donc produit en g\xE9n\xE9ral des boites de grande hauteur et faible profondeur. \xC0 l'oppos\xE9, \idx\vtop produit des empilements ayant des \xE9l\xE9ments sous cette \idx{ligne de base} et donc des boites de petite hauteur et grande profondeur.
+\grandsaut
+
+Dans l'exemple ci-dessous, on met dans une \idx\vbox et une \idx\vtop des \xE9l\xE9ments dont la largeur est contr\xF4l\xE9 puisque ce sont des \idx\hbox. On peut observer, gr\xE2ce aux points qui repr\xE9sentent approximativement la \idx{ligne de base} la diff\xE9rence fondamentale entre une \idx\vbox et une \idx\vtop :
+
+\showcode/Ligne de base : .........%
+\vbox{\hbox{ligne du haut}\hbox{ligne du milieu}\hbox{ligne du bas}}%\xA4\idx*\vbox\xA4
+.........%
+\vtop{\hbox{ligne du haut}\hbox{ligne du milieu}\hbox{ligne du bas}}.........\xA4\idx*\vtop\xA4/
+
+Voici ce qui se passe en dessinant les boites et leur \idx{point de r\xE9f\xE9rence} :
+
+\begin{centrage}
+\footnotesize
+\leavevmode\setbox0=\hbox{ligne du milieu}
+Ligne de base.........%
+\drawbox{\vbox{\raggedright\hsize\wd0 \drawbox{ligne du haut}\par\drawbox{ligne du milieu}\par\drawbox{ligne du bas}}}%
+.........%
+\drawbox{\vtop{\raggedright\hsize\wd0 \drawbox{ligne du haut}\par\drawbox{ligne du milieu}\par\drawbox{ligne du bas}}}%
+.........%
+\end{centrage}
+
+Nous allons maintenant faire de m\xEAme avec un \xE9l\xE9ment dont la largeur n'est pas contr\xF4l\xE9e, c'est-\xE0-dire un paragraphe entier compos\xE9 de deux phrases identiques contenues dans la macro \verb|\dummytext|. Afin que les deux boites tiennent horizontalement dans l'espace qui leur est r\xE9serv\xE9, la largeur des boites verticales sera impos\xE9e par \idx\hsize \xE0 \numprint[cm]4 :
+
+\showcode/\def\dummytext{Bla, bla, bla, un texte sans importance. }
+Ligne de base.........%
+\vbox{\hsize=4cm \dummytext\dummytext}%\xA4\idx*\vbox\xA4
+.........%
+\vtop{\hsize=4cm \dummytext\dummytext}.........\xA4\idx*\vtop\xA4/
+
+\subsection{Registres de boite}\idx*[|(]{boite!registre}
+Une boite simplement affich\xE9e avec \idx\hbox, \idx\vbox ou \idx\vtop ne permet pas de travailler sur cette boite. En revanche, une boite \emph{stock\xE9e} dans un registre ouvre d'autres perspectives puisqu'elle est m\xE9moris\xE9e par \TeX. D\xE8s lors, il devient possible d'effectuer des op\xE9rations sur ces boites.
+
+Avant de poursuivre, il encore une fois est important de clarifier le sens du mot \xAB stockage \xBB. Autant les macros et les registres de tokens stockent du \emph{code source tok\xE9niz\xE9} c'est-\xE0-dire du mat\xE9riau brut initial, autant les registres de boites stockent d'un c\xF4t\xE9 le r\xE9sultat typographique d'un \verb|<code>| une fois qu'il a \xE9t\xE9 compos\xE9 et de l'autre les assignations faites dans ce \verb|<code>|. Le stockage par macro et par boite sont deux stockages oppos\xE9s en ce sens que chacun effectue une sauvegarde \xE0 l'un des deux bouts de la chaine qui m\xE8ne du code source \xE0 l'affichage final.
+\grandsaut
+
+Nous commen\xE7ons \xE0 \xEAtre familiers avec les registres puisque, hormis les macros, il en existe pratiquement pour chaque type de donn\xE9e que manipule \TeX{} (tokens, entiers, dimensions, ressorts). Les boites ne font \xE9videmment pas exception \xE0 la r\xE8gle, m\xEAme si la syntaxe des registres de boites est l\xE9g\xE8rement diff\xE9rente de celle des autres registres. La raison incombe au fait que \TeX{} ne poss\xE8de pas de primitive \verb|\boxdef| alors qu'il poss\xE8de \idx\toksdef, \idx\countdef, \idx\dimendef et \idx\skipdef.
+
+\begin{regle}
+\relax\TeX{} dispose de 256 registres de boites (\numprint{32768} avec \idx\eTeX).
+
+On demande \xE0 \TeX{} d'allouer un num\xE9ro de registre de boite par l'interm\xE9diaire de la macro \idx\newbox\verb|\<macro>| et ce faisant, l'assignation suivante est faite
+
+\centrecode-\global\chardef\<macro>=<nombre>-
+
+o\xF9 le \verb|<nombre>| est un num\xE9ro de registre de boite libre.
+
+Ce faisant, la \verb|\<macro>| devient \xE9quivalente \xE0 \idx\char\verb|<nombre>|. Ainsi, \verb|\<macro>| produit le caract\xE8re de code \verb|<nombre>|, mais lorsque \TeX{} s'attend \xE0 lire un nombre (comme c'est le cas lorsqu'il attend un num\xE9ro de boite), \verb|\<macro>| est lue comme l'entier \verb|<nombre>|. Du point de vue de la m\xE9canique interne, un \verb|<registre>| de boite est donc un \verb|<nombre>|.
+
+On acc\xE8de \xE0 la boite contenue dans un registre par \idx\box\verb|<registre>|.
+
+Pour proc\xE9der \xE0 l'assignation, on \xE9crit\idx*{assignation!registre de boite}\idx*\setbox :
+
+\centrecode-\setbox<registre>= <boite valide>-
+
+\noindent o\xF9 une \verb|<boite valide>| est soit une boite contenue dans un registre et \xE9crite sous la forme \idx\box\verb|<registre>|, soit une boite construite avec les primitives \idx\hbox, \idx\vbox ou \idx\vtop. Le signe \verb|=| et l'espace qui le suit sont facultatifs.
+
+Pour afficher une boite stock\xE9e dans un \verb|<registre>|, on \xE9crit \idx\box\verb|<registre>|. La boite est affich\xE9e selon le mode en cours (horizontal ou vertical) : le type de boite n'a pas d'influence sur le mode dans lequel elle est affich\xE9e.
+
+Lorsqu'on utilise la primitive \idx\box pour acc\xE9der \xE0 la boite stock\xE9e dans un registre, la boite contenue dans le registre est irr\xE9m\xE9diablement perdue et le registre devient vide, c'est-\xE0-dire qu'il ne contient aucune boite. Si on souhaite conserver la boite dans le registre, on doit utiliser la primitive \idx\copy au lieu de \idx\box.
+\end{regle}
+
+\begin{regle}
+Le test\tidx*{ifvoid}%
+
+\centrecode-\ifvoid<registre><code vrai>\else<code faux>\fi-
+
+se comporte comme les autres tests de \TeX. Il revoit \verb|<code vrai>| si le \verb|<registre>| de boite est vide (c'est-\xE0-dire s'il ne contient aucune boite).
+\end{regle}
+
+Il est admis que la boite \no0\idx*{boite!\no0} est une boite \xAB brouillon \xBB qui peut \xEAtre utilis\xE9e ponctuellement si l'on ne veut pas mobiliser un nouveau registre de boite.
+\grandsaut
+
+L'exemple ci-dessous illustre ce que nous venons d'aborder. Nous allons tout d'abord allouer un nouveau registre \verb|\foobox| par \idx\newbox et nous y stockerons une boite horizontale contenant le mot \xAB foobar \xBB. Ensuite, nous allons utiliser le test \tidx{ifvoid} dans plusieurs cas de figure afin de montrer que le registre devient vide apr\xE8s avoir ex\xE9cut\xE9 la primitive \idx\box.
+
+\showcode/\newbox\foobox\xA4\idx*\newbox\xA4
+a) \setbox\foobox=\hbox{foobar}% registre non vide\xA4\idx*\setbox\xA4
+   Le registre est \ifvoid\foobox vide\else non vide\fi\par
+b) \setbox\foobox=\hbox{foobar}
+   "\box\foobox" et le registre est \ifvoid\foobox vide\else non vide\fi\par
+c) \setbox\foobox=\hbox{foobar}
+   "\copy\foobox" et le registre est \ifvoid\foobox vide\else non vide\fi\par
+d) \setbox\foobox=\hbox{}
+   Le registre est \ifvoid\foobox vide\else non vide\fi\xA4\tidx*{ifvoid}\xA4/
+
+On remarque que \idx\box vide le registre (cas b) tandis que \idx\copy le pr\xE9serve (cas c). Il est \xE9galement important de noter que le registre n'est pas vide (cas d) s'il contient une boite vide.
+\grandsaut
+
+Deux autres tests sur les registres de boite m\xE9ritent d'\xEAtre signal\xE9s :
+
+\begin{centrage}
+\small\tidx{ifhbox}\verb|<registre>|\quad et\quad\tidx{ifvbox}\verb|<registre>|
+\end{centrage}
+
+\noindent sont vrais si le \verb|<registre>| contient respectivement une boite horizontale ou verticale.\idx*[|)]{boite!registre}
+
+\subsection{Dimensions des boites}\idx*[|(]{boite!dimension}
+\begin{regle}
+Les dimensions d'une boite stock\xE9e dans un \verb|<registre>| sont :
+\begin{itemize}
+	\item sa longueur horizontale, accessible par \idx\wd\verb|<registre>| ;
+	\item sa hauteur, qui s'\xE9tend au-dessus de la \idx{ligne de base}, accessible par \idx\ht{}\linebreak[1]\verb|<registre>| ;
+	\item enfin, sa profondeur qui s'\xE9tend au-dessous de la \idx{ligne de base} et qui est accessible par \idx\dp\verb|<registre>|.
+\end{itemize}
+
+Les primitives \idx\wd, \idx\ht et \verb|\dp| suivies d'un \verb|<registre>| se comportent comme des registres de dimension.
+\end{regle}
+
+\noindent Pour fixer les id\xE9es, voici un sch\xE9ma o\xF9 les \idx*{boite!englobante}boites englobantes, rectangles qui repr\xE9sentent l'encombrement d'une boite tel qu'il est pris en compte par \TeX, sont trac\xE9es et les trois dimensions sont \xE9crites pour quatre lettres diff\xE9rentes :\medbreak
+
+\noindent\hskip0.1\linewidth\hbox to0pt{\dimenbox{g}\hss}\hskip0.5\linewidth\hbox to0pt{\dimenbox{o}\hss}\medbreak
+\noindent\hskip0.1\linewidth\hbox to0pt{\dimenbox{P}\hss}\hskip0.5\linewidth\hbox to0pt{\dimenbox{\itshape f}\hss}\medbreak
+
+On peut observer notamment avec la lettre \xAB\textit{f}\kern1pt\xBB que la boite englobante\idx*{boite!englobante} ne correspond pas \xE0 la plus petite boite qui contient les contours de la lettre. Pour d'\xE9videntes raisons de typographie, il est \emph{n\xE9cessaire} que certaines parties de la lettre \xAB\textit{f}\xBB d\xE9passent de la boite englobante\idx*{boite!englobante} sinon, au lieu de \xAB\textit{foo}\xBB, nous aurions un horrible \xAB\textit{f\kern1.65ptoo}\xBB !
+
+De plus, contrairement \xE0 ce que l'on pourrait croire, la profondeur de lettres comme \xABo\xBB ou \xABP\xBB n'est pas nulle ! Tr\xE8s faible certes, mais pas nulle\ldots{} Le concepteur de la \idx{fonte} \xABLibertine\xBB avec laquelle est \xE9crit ce livre en a d\xE9cid\xE9 ainsi.
+\grandsaut
+
+Passons \xE0 la pratique et mesurons maintenant les dimensions de boites construites successivement avec les trois primitives \idx\hbox, \idx\vbox et \idx\vtop. Les boites verticales seront des empilements de \idx\hbox, chacune contenant un mot de la phrase \xABProgrammer est facile.\xBB
+
+\showcode/\newbox\foobox\xA4\idx*\newbox\xA4
+\setbox\foobox=\hbox{Programmer est facile.}\xA4\idx*\setbox\xA4
+<<\copy\foobox>>\xA4\idx*\copy\xA4
+mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut.\xA4\idx*\the\idx*\wd\idx*\dp\xA4
+\medbreak\xA4\idx*\medbreak\xA4
+
+\setbox\foobox=\vbox{\hbox{Programmer}\hbox{est}\hbox{facile.}}\xA4\idx*\setbox\xA4
+<<\copy\foobox>>
+mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut.
+\medbreak\xA4\idx*\medbreak\xA4
+
+\setbox\foobox=\vtop{\hbox{Programmer}\hbox{est}\hbox{facile.}}\xA4\idx*\setbox\idx*\vtop\xA4
+<<\copy\foobox>>
+mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut.\xA4\idx*\the\idx*\wd\idx*\dp\xA4/
+
+La faible profondeur de la \idx\vbox provient une fois encore du design de la \idx{fonte} Libertine qui donne une faible profondeur \xE0 certaines lettres qui composent le mot du bas \xABfacile\xBB. La verticalit\xE9 \emph{totale} des boites verticales (c'est-\xE0-dire la somme de leur hauteur et de leur profondeur) \idx\vbox et \idx\vtop est la m\xEAme dans les deux cas.
+
+\begin{exercice}
+Programmer une macro \xA7\vdim\verb|{<registre>}| qui calcule la verticalit\xE9 de la boite contenue dans le \verb|<registre>|.
+\solution
+Il suffit de donner \xE0 \idx\dimexpr l'addition de sa hauteur et sa profondeur :
+
+\showcode/\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}\xA4\xA7*\vdim\xA4
+a) \setbox\foobox=\vbox{\hbox{Programmer}\hbox{est}\hbox{facile.}}\xA4\idx*\setbox\xA4
+   Verticalit\xE9 de la \litterate-\vbox- = \the\vdim\foobox\par\xA4\xA7*\litterate\idx*\the\xA4
+b) \setbox\foobox=\vtop{\hbox{Programmer}\hbox{est}\hbox{facile.}}\xA4\idx*\setbox\xA4
+   Verticalit\xE9 de la \litterate-\vtop- = \the\vdim\foobox\xA4\xA7*\litterate\idx*\the\xA4/
+\end{exercice}
+
+\begin{exercice}
+Inventer un proc\xE9d\xE9 qui permette de compter combien de caract\xE8res affichables contient un argument. On appellera la macro \xA7\countallchar\verb|{<texte>}| et on supposera que le \verb|<texte>| est uniquement constitu\xE9 de caract\xE8res affichables (catcodes 11 et 12) et d'espaces.
+\solution
+Au point o\xF9 nous en sommes, la solution la plus imm\xE9diate est de mettre cet argument dans une boite \idx\hbox o\xF9 la \idx{fonte} sera \xE0 chasse fixe. Il suffit de mesurer cette boite, de mesurer un caract\xE8re et d'effectuer la division entre les entiers contraints de ces deux dimensions pour afficher le nombre de caract\xE8res. Ici, nous allons m\xEAme afficher la division conduisant au r\xE9sultat :
+
+\showcode|\def\countallchar#1{%\xA4\xA7*\countallchar\xA4
+	Il y a %
+	\setbox0=\hbox{\tt#1}% met #1 dans la boite\xA4\idx*\setbox\xA4
+	\edef\arglength{\number\wd0 }% stocke la largeur de la boite en sp\xA4\idx*\number\idx*\wd\idx*{sp (unit\xE9)}\xA4
+	\setbox0=\hbox{\tt A}% met "A" dans la boite\xA4\idx*\setbox\xA4
+	\edef\charlength{\number\wd0 }% stocke la largeur d'un caract\xE8re
+	$\number\arglength/\charlength % affiche la division\xA4\idx*\wd\xA4
+	=\number\numexpr\arglength/\charlength\relax$ % affiche le quotient\xA4\idx*\wd\xA4
+	caract\xE8res%
+}
+\countallchar{abcd efgh}\par
+\countallchar{A5 xW5 64 a1}\par
+\countallchar{affligeant}\xA4\xA7*\countallchar\xA4|
+
+Une m\xE9thode similaire peut \xEAtre d\xE9ploy\xE9e pour compter combien de fois figure un caract\xE8re affichable $\alpha$ dans un argument. L'id\xE9e est de mesurer la boite contenant l'argument compos\xE9 en fonte \xE0 chasse fixe et stocker cette longueur dans $L$. Ensuite, le caract\xE8re $\alpha$ est supprim\xE9 avec la macro \xA7\substin et la man\oe uvre est r\xE9p\xE9t\xE9e : $l$ est la nouvelle longueur. Le nombre d'occurrences de $\alpha$ est la diff\xE9rence $L-l$ divis\xE9e par la longueur de la boite contenant $\alpha$ :
+
+\showcode|\catcode`@11
+\def\countchar#1#2{%
+		\setbox\z@\hbox{\tt#2}% met #2 dans boite 0\xA4\idx*\setbox\idx*\tt \xA7*\defactive\idx*\string\idx*\hbox\idx*\z@\xA4
+		\edef\len at a{\number\wd\z@}% mesure la boite\xA4\idx*\wd\xA4
+		\setbox\z@\hbox{\tt\substin{#2}{#1}{}}% recommencer sans "#1"\xA4\idx*\setbox\xA7*\defactive\xA4
+		\edef\len at b{\number\wd\z@}% mesure la boite
+		\setbox\z@\hbox{\tt A}% met "A" dans la boite\xA4\idx*\setbox\idx*\string\xA4
+		\edef\charlength{\number\wd\z@}% stocke la largeur du caract\xE8re
+		\number\numexpr(\len at a-\len at b)/\charlength% et affiche le quotient
+}
+\catcode`@12
+a) \countchar{a}{abracadabra}\qquad
+b) \countchar{b}{zigzag}\qquad
+c) \countchar{ }{a bc de f ghi j k }\xA4\xA7*\countchar\xA4|
+\end{exercice}\idx*[|)]{boite!dimension}
+
+\subsection{D\xE9placer des boites}\idx*[|(]{boite!d\xE9placement}
+\TeX{} met \xE0 disposition des primitives pour d\xE9placer des boites dans la direction que l'on veut (haut, bas, gauche, droite).
+
+\begin{regle}
+Les primitives \idx\lower ou \idx\raise doivent \xEAtre suivies d'une \verb|<dimension>|, le tout devant pr\xE9c\xE9der une boite horizontale, qu'elle soit \xE9crite par l'interm\xE9diaire de \idx\hbox ou d'un registre. L'effet est d'abaisser pour \idx\lower ou d'\xE9lever pour \idx\raise la boite de la \verb|<dimension>| sp\xE9cifi\xE9e.
+
+Les primitives \idx\moveleft et \idx\moveright partagent la m\xEAme syntaxe, mais agissent sur des boites \emph{verticales} en les d\xE9pla\xE7ant vers la gauche ou vers la droite.
+\end{regle}
+
+Voici comment on peut enfermer des mots dans une \idx\hbox et les \xE9lever ou les abaisser d'une dimension arbitraire :
+
+\showcode/Programmer \raise1ex\hbox{en} \lower1ex\hbox{\TeX} \lower2ex\hbox{est} facile.\xA4\idx*\raise\idx*\lower\idx*\hbox\xA4/
+
+Il faut d'ailleurs noter que le logo \xAB\TeX\xBB, obtenu en ex\xE9cutant la macro \index{TeX@\texttt{\char92 TeX}}\verb|\TeX|, est construit en utilisant \idx\lower pour abaisser la lettre \xABE\xBB apr\xE8s rebrouss\xE9 chemin vers la gauche \xE0 l'aide de \idx\kern. La lettre \xABX\xBB est \xE9galement d\xE9plac\xE9e vers la gauche avec un autre \idx\kern. Voici comment est d\xE9finie la macro \index{TeX@\texttt{\char92 TeX}}\TeX{} par plain-\TeX :
+
+\centrecode|\def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX}|
+\grandsaut
+
+Il peut sembler frustrant que l'on ne puisse pas \xAB centrer \xBB une boite contenant du mat\xE9riel vertical par rapport \xE0 l'axe qu'est la \idx{ligne de base} puisque \idx\vbox et \idx\vtop empilent ce mat\xE9riel respectivement au-dessus ou au-dessous de cette ligne. L'id\xE9e serait d'abaisser ces boites avec \idx\lower de la dimension \xE9gale \xE0
+
+\[\frac{\hbox{hauteur}-\hbox{profondeur}}2\]
+
+\noindent \xE9tant entendu que si cette quantit\xE9 est n\xE9gative, abaisser d'une dimension n\xE9gative revient \xE0 \xE9lever la boite. En coulisses, cette m\xE9thode nous contraint \xE0 mettre la boite dans un registre pour pouvoir la mesurer afin d'acc\xE9der \xE0 sa hauteur et sa profondeur. La macro \xA7\cbox va mettre en application cette m\xE9thode et sera amen\xE9e \xE0 recevoir du mat\xE9riel vertical dans les m\xEAmes conditions que \idx\vbox afin de centrer la boite par rapport \xE0 la \idx{ligne de base} :
+
+\showcode|\def\cbox#1{%\xA4\xA7*\cbox\xA4
+	\setbox0\vbox{#1}% met le contenu dans une \vbox\xA4\idx*\setbox\idx*\vbox\xA4
+	\lower\dimexpr(\ht0-\dp0)/2\relax\box0 % l'abaisse\xA4\idx*\lower\idx*\dimexpr\idx*\ht\idx*\dp\idx*\box\xA4
+}
+
+......\cbox{\hbox{$x^2$}}......\cbox{\hbox{foo}\hbox{et bar}}......%
+\cbox{\hbox{Programmer}\hbox{en \TeX}\hbox{est facile}}.......\xA4\xA7*\cbox\xA4|
+
+\TeX{} dispose de la primitive \idx\vcenter, qui fonctionne en mode math\xE9matique\idx*{mode!math\xE9matique}, dont l'argument est constitu\xE9 de mat\xE9riel vertical (comme l'est celui de \idx\vbox ou \idx\vtop) et qui place la boite ainsi cr\xE9\xE9 de telle sorte que ses fronti\xE8res haute et basse soient \xE9quidistantes de \xABl'axe math\xE9matique\xBB. Deux pr\xE9cisions doivent \xEAtre apport\xE9es :
+
+\begin{itemize}
+	\item la primitive ne peut \xEAtre appel\xE9e qu'en mode math\xE9matique\idx*{mode!math\xE9matique}, mais le contenu de la boite n'h\xE9rite pas de ce mode, c'est-\xE0-dire qu'il sera compos\xE9 en mode texte, sauf si bien s\xFBr, on demande explicitement \xE0 passer en mode math\xE9matique\idx*{mode!math\xE9matique} \xE0 l'int\xE9rieur de la boite (les boites \idx\hbox, \idx\vbox et \idx\vtop partagent aussi cette propri\xE9t\xE9) ;
+	\item l'axe math\xE9matique \emph{n'est pas} \xE0 la m\xEAme hauteur que la \idx{ligne de base}; il s'agit de deux axes diff\xE9rents. L'axe math\xE9matique est horizontal et se trouve approximativement \xE0 \xE9quidistance des traits horizontaux du signe \xAB$=$\xBB. Il repr\xE9sente l'axe de sym\xE9trie horizontal de plusieurs signes math\xE9matiques alors que la \idx{ligne de base} est approximativement tangente au bas des lettres qui n'ont pas de jambage comme on le voit dans l'\xE9galit\xE9 ci-dessous :
+	\begin{centrage}
+		\begingroup\huge
+		\setbox0\hbox{$\vcenter{}$}%
+		\xdef\htmath{\the\ht0}%
+		\endgroup
+		\begin{tikzpicture}[inner sep=0pt,outer sep=0pt,minimum size=0pt,baseline,line width=0.2pt]
+			\node[anchor=base west](equation){\huge $a\kern.125em(b+c)=ab+ac$};
+			\draw[gray]([xshift=-2cm]equation.base west)--([xshift=0.2cm]equation.base east)node[pos=0,anchor=south west,outer sep=1pt,black]{\scriptsize ligne}node[pos=0,anchor=north west,outer sep=1pt,black]{\scriptsize de base};
+			\draw[gray]([xshift=-0.2cm,yshift=\htmath]equation.base west)--([xshift=2cm,yshift=\htmath,black]equation.base east)node[pos=1,anchor=south east,outer sep=1pt,black]{\scriptsize axe}node[pos=1,outer sep=1pt,anchor=north east,black]{\scriptsize math};
+		\end{tikzpicture}
+	\end{centrage}
+\end{itemize}
+
+Par cons\xE9quent, une boite centr\xE9e avec \idx\vcenter ne sera pas exactement \xE0 la m\xEAme hauteur que la m\xEAme boite centr\xE9e avec la macro \xA7\cbox vue pr\xE9c\xE9demment. La diff\xE9rence se voit sans peine \xE0 l'\oe il nu dans cet exemple :
+
+\showcode|......\cbox{\hbox{foo}\hbox{et bar}}......$\vcenter{\hbox{foo}\hbox{et bar}}$......\xA4\idx*\vcenter\xA7*\cbox\xA4|\idx*[|)]{boite!d\xE9placement}
+
+\begin{exercice}
+Inventer un proc\xE9d\xE9 pour que la macro \xA7\htmath affiche \xE0 quelle distance de la ligne de base se trouve l'axe math\xE9matique.
+\solution
+Si une \idx\hbox contient une \idx\vcenter vide, la hauteur de la \idx\hbox sera pr\xE9cis\xE9ment la distance cherch\xE9e.
+
+\showcode/\def\htmath{\begingroup\xA4\xA7*\htmath\xA4
+	\setbox0=\hbox{$\vcenter{}$}\the\ht0 \xA4\idx*\setbox\idx*\vcenter\idx*\the\idx*\ht\xA4
+\endgroup
+}
+L'axe math\xE9matique se trouve \xE0 \htmath{} de la ligne de base./
+\end{exercice}
+
+\subsection{Choisir la dimension d'une boite}\idx*[|(]{boite!dimension choisie}
+\begin{regle}
+On peut imposer une dimension aux boites en le sp\xE9cifiant avec le mot-cl\xE9 \xAB\idx*{boite!mot-cl\xE9 \xABto\xBB}\verb|to|\xBB suivi d'un espace optionnel puis d'une \verb|<dimension>|. Et donc, si l'on \xE9crit
+
+\centrecode-\hbox to 3cm{<contenu>}-
+
+\noindent cela cr\xE9era une boite horizontale de longueur \numprint[cm]{3}, quel que soit le \verb|<contenu>|. Si le contenu ne mesure pas \emph{exactement} \numprint[cm]{3} et ne contient aucun \xE9l\xE9ment \xE9tirable, il y aura soit un d\xE9bordement, soit un sous-remplissage de boite, chacun respectivement signal\xE9 par les messages d'avertissement\idx*{message d'avertissement} \xAB\texttt{Overfull \string\hbox}\xBB ou \xAB\texttt{Underfull \string\hbox}\xBB dans le \idx[!log]{fichier} \verb|log|. La m\xEAme syntaxe s'applique pour \idx\vbox et \idx\vtop sauf que la dimension est impos\xE9e dans le sens \emph{vertical}.
+
+On peut \xE9galement \xE9crire le mot-cl\xE9 \xAB\idx*{boite!mot-cl\xE9 \xABspread\xBB}\verb|spread|\xBB utilis\xE9 \xE0 la place de \xAB\verb|to|\xBB si l'on souhaite construire une boite dont la dimension finale sera sa dimension naturelle augment\xE9e de la \verb|<dimension>|. Si cette dimension est n\xE9gative, la boite cr\xE9\xE9e aura une dimension inf\xE9rieure \xE0 sa dimension naturelle.
+\end{regle}
+
+Voici un exemple qui montre comment une boite est affich\xE9e avec sa largeur naturelle puis \xE9tir\xE9e de \verb|5pt| et \verb|10pt| gr\xE2ce \xE0 un ressort \idx\hfil plac\xE9 entre les syllabes \xAB\verb|foo|\xBB et \xAB\verb|bar|\xBB:
+
+\showcode/1) \hbox{foobar}\par\xA4\idx*\hbox\xA4
+2) \hbox spread 5pt{foo\hfil bar}\par
+3) \hbox spread10pt{foo\hfil bar}/
+
+\Qu e ce soit via \xAB\verb|to|\xBB ou \xAB\verb|spread|\xBB, il est n\xE9cessaire que contenu de la boite ait un ou plusieurs ressorts. Ils devront avoir des composantes \xE9tirables convenablement choisies pour qu'en s'\xE9tirant ou en se comprimant, ils puissent compenser l'exc\xE8s ou le manque de place pour le contenu. Un des ressorts les plus utilis\xE9s dans ce cas est \idx\hss pour les boites horizontales et \idx\vss pour les boites verticales. Rappelons qu'ils ont une longueur nulle et peuvent s'\xE9tirer ou se comprimer infiniment.
+\grandsaut
+
+On peut facilement cr\xE9er des macros qui affichent du texte \emph{en surimpression} soit \xE0 droite, soit \xE0 gauche de la position courante. Ces deux macros, \idx\rlap et \idx\llap, dont le nom signifie \xAB right overlap \xBB (surimpression vers la droite) ou \xAB left overlap \xBB (surimpression vers la gauche) sont ainsi d\xE9finies dans le \idx[!plain-\TeX]{format} plain-\TeX :
+
+\centrecode-\def\rlap#1{\hbox to\z@{#1\hss}}\xA4\idx*\z@\xA4
+\def\llap#1{\hbox to\z@{\hss#1}}-
+
+Examinons tout d'abord \idx\rlap. Son argument \verb|#1| est mis dans une boite horizontale de longueur nulle (\idx\z@ repr\xE9sente la dimension \verb|0pt|). Un sur-remplissage de la boite semble in\xE9vitable, car le contenu \verb|#1| prend une certaine place horizontale. C'est l\xE0 que le ressort \idx\hss plac\xE9 en fin de boite va intervenir : pour satisfaire la longueur de la boite nulle, il va se comprimer pour atteindre une longueur n\xE9gative exactement \xE9gale \xE0 l'oppos\xE9 de la longueur de l'argument \verb|#1|. La somme des longueurs de \verb|#1| et de \idx\hss satisfait bien la dimension nulle impos\xE9e.
+
+\begin{centrage}
+	\footnotesize
+	\begin{tikzpicture}
+		\useasboundingbox (-3,-2) rectangle (4,1);
+		\draw[line width=1pt](0,-2)--(0,0)node[above,align=center,text width=1.5cm]{Position courante};
+		\node[draw,anchor=mid west,align=center,text width=3cm,inner sep=0pt,outer sep=0pt](arg1)at(0,-.5){\vrule height2.5ex depth1.5ex width0pt Argument \ttfamily \#1}node[anchor=mid west] at(4,-.5){\xC9tape \no1};
+		\draw [-stealth](.15,-1.5)--(0,-1.5);
+		\draw[decorate,decoration={zigzag,segment length=0.3cm,amplitude=1mm}] (.15,-1.5)--(3cm,-1.5)
+			node[below,pos=.5,yshift=-.1cm]{ressort \ttfamily\string\hss}
+			node[anchor=mid west] at(4,-1.5){\xC9tape \no2};
+	\end{tikzpicture}
+\end{centrage}
+
+Son homologue \idx\llap fonctionne de la m\xEAme fa\xE7on sauf que le ressort \idx\hss est plac\xE9 en d\xE9but de boite : il va donc se comprimer en premier ce qui se traduit \xE0 l'affichage par un recul vers la gauche de la longueur de \verb|#1|. Ensuite, \verb|#1| est compos\xE9 et rattrape exactement la longueur n\xE9gative de \idx\hss.
+
+\begin{centrage}
+	\footnotesize
+	\begin{tikzpicture}
+		\useasboundingbox (-3,-2) rectangle (4,1.5);
+		\draw[line width=1pt](0,-2)--(0,0.5)node[above,align=center,text
+ width=1.5cm]{Position courante};
+		\node[draw,anchor=mid east,align=center,text width=3cm,inner sep=0pt,outer sep=0pt](arg1)at(0,-1.5){\vrule height2.5ex depth1.5ex width0pt Argument\ttfamily  \#1}node[anchor=mid west] at(.5,-1.5){\xC9tape \no2};
+		\draw [-stealth](-2.85,-.5)--(-3,-.5);
+		\draw[decorate,decoration={zigzag,segment length=0.3cm,amplitude=1mm}] (-2.85cm,-0.5)--(0,-0.5)
+			node[above,pos=.5,yshift=.1cm]{ressort \ttfamily\string\hss}
+			node[anchor=mid west] at(.5,-0.5){\xC9tape \no1};
+	\end{tikzpicture}
+\end{centrage}
+
+L'exemple ci-dessous montre comment ces deux macros peuvent utilis\xE9es pour \xE9crire soit \xE0 gauche, soit \xE0 droite de la position courante en surimpression. Dans les deux cas, le caract\xE8re \xAB|\xBB est utilis\xE9 pour symboliser la position courante lorsque \TeX{} rencontre ces deux macros :
+
+\showcode=foobar|\rlap{/////}123456\qquad foobar|\llap{/////}123456\xA4\idx*\rlap\idx*\llap\xA4=
+
+Il est curieux que \idx*{Knuth Donald}D.~\textsc{Knuth} n'ait pas impl\xE9ment\xE9 la macro \xA7\clap qui permettrait de centrer le contenu de son argument sur la position courante sans que l'encombrement horizontal ne soit pris en compte :
+
+\centrecode-\def\clap#1{\hbox to0pt{\hss#1\hss}}-\xA7*\clap
+
+Bien s\xFBr, le fonctionnement de cette macro est en tout point semblable \xE0 \idx\rlap et \idx\llap sauf que les deux ressorts se compriment de fa\xE7on identique ce qui donne un centrage du contenu par rapport \xE0 la position courante:
+
+\begin{centrage}
+	\footnotesize
+	\begin{tikzpicture}
+		\useasboundingbox (-3,-3) rectangle (4,1);
+		\draw[line width=1pt](0,-3)--(0,0)node[above,align=center,text width=1.5cm]{Position courante};
+		\draw [-stealth](-1.35,-.5)--(-1.5,-.5);
+		\draw[decorate,decoration={zigzag,segment length=0.3cm,amplitude=1mm}] (-1.35cm,-0.5)--(0,-0.5)
+			node[below,pos=.5,yshift=-.1cm]{\ttfamily\string\hss}
+			node[anchor=mid west] at(2,-0.5){\xC9tape \no1};
+		\node[draw,align=center,text width=3cm,inner sep=0pt,outer sep=0pt](arg1)at(0,-1.5){\vrule height2.5ex depth1.5ex width0pt Argument \ttfamily\#1}node[anchor=mid west] at(2,-1.5){\xC9tape \no2};
+		\draw [-stealth](0.15,-2.5)--(0,-2.5);
+		\draw[decorate,decoration={zigzag,segment length=0.3cm,amplitude=1mm}] (1.5,-2.5)--(.15,-2.5)
+			node[below,pos=.5,yshift=-.1cm]{\ttfamily\string\hss}
+			node[anchor=mid west] at(2,-2.5){\xC9tape \no3};
+	\end{tikzpicture}
+\end{centrage}
+
+Des effets d'empilement peuvent \xEAtre cr\xE9\xE9s avec les macros \idx\raise et \idx\lower qui d\xE9placent verticalement la prochaine boite horizontale d'une dimension choisie :
+
+\showcode/\def\clap#1{\hbox to0pt{\hss#1\hss}}\xA4\idx*\hss\xA7*\clap\xA4
+a) avant la macro|\clap{SURIMPRESSION}apr\xE8s la macro\medbreak
+b) avant la macro|\raise2.5ex\clap{Au-dessus}\lower2.5ex\clap{Au-dessous}%
+   apr\xE8s la macro\medbreak\xA4\idx*\raise\idx*\lower\xA7*\clap\xA4
+c) avant la macro|\raise2.5ex\llap{Au-dessus avant}\lower2.5ex\rlap{Au-dessous apr\xE8s}%
+   apr\xE8s la macro\xA4\idx*\rlap\idx*\llap\xA4/\idx*[|)]{boite!dimension choisie}
+
+\newpage% TODO : pour ne pas que le titre de la sous section soit orphelin en bas de page
+\subsection{Redimensionner une boite}\idx*[|(]{boite!redimensionnement}
+\begin{regle}
+Une fois qu'une boite est stock\xE9e dans un \verb|<registre>|, il est possible de modifier une ou plusieurs de ses dimensions. Il suffit d'\xE9crire
+
+\begin{centrage}
+\small$\left.\vcenter{\ttfamily\hbox{\string\wd}\hbox{\string\ht}\hbox{\string\dp}}\right\}$\verb|<registre>= <dimension>|\idx*\wd\idx*\ht\idx*\dp
+\end{centrage}
+
+\noindent pour que la largeur, hauteur ou profondeur de la boite prenne la dimension indiqu\xE9e, ind\xE9pendamment de ce qu'est le contenu de la boite. Ces assignations sont toujours \emph{globales}\idx*{assignation!toujours globale}. En proc\xE9dant de cette fa\xE7on, le contenu reste intact, mais \TeX{} est tromp\xE9 et voit d\xE9sormais la boite avec les nouvelles dimensions.
+\end{regle}
+
+Un peu \xE0 la mani\xE8re de \idx\rlap, il devient ainsi possible de superposer une boite au texte qui la suit :
+
+\showcode |\setbox0=\hbox{\tt//////////}\xA4\idx*\tt\idx*\setbox\xA4
+\wd0=0pt % fait croire \xE0 TeX que la larguer de la boite est nulle\xA4\idx*\wd\xA4
+Voici \copy0 du texte partiellement barr\xE9...\xA4\idx*\copy\xA4|
+
+Est-il possible de redonner au contenu d'une boite ainsi modifi\xE9e une nouvelle virginit\xE9 quant \xE0 ses dimensions, et faire en sorte que ce contenu occupe \xE0 nouveau ses dimensions naturelles ?
+
+\begin{regle}
+Si un \verb|<registre>| de boite contient une boite horizontale ou verticale, il est possible d'extraire le contenu de la boite avec \idx\unhbox\verb|<registre>| ou \idx\unvbox\verb|<registre>|. La liste horizontale ou verticale contenue dans la boite est alors ajout\xE9e \xE0 la liste courante en cours. Apr\xE8s cette op\xE9ration, le registre de boite devient vide, c'est \xE0 dire positif au sens de \tidx{ifvoid}.
+
+Pour ne pas vider le registre de boite, il faut employer \idx\unhcopy ou \idx\unvcopy.
+\end{regle}
+
+L'important \xE0 retenir de cette r\xE8gle est que la liste ainsi extraite retrouve ses dimensions naturelles, m\xEAme si les dimensions de la boite avaient \xE9t\xE9 modifi\xE9es apr\xE8s coup.
+
+\showcode/\def\printdim{largeur=\the\wd0 \qquad hauteur=\the\ht0 \qquad profondeur = \the\dp0 }\xA4\idx*\the\idx*\wd\idx*\ht\xA4
+\setbox0=\hbox{Programmer en \TeX{} est facile}\xA4\idx*\setbox\xA4
+a) \printdim\par
+b) \wd0=0pt \ht0=0pt \dp0=0pt% rend toutes le dimensions nulles\xA4\idx*\wd\idx*\ht\idx*\dp\xA4
+   \printdim\par
+c) \setbox0=\hbox{\unhbox0 }% reprend les dimensions d'origine\xA4\idx*\hbox\idx*\unhbox\idx*\setbox\xA4
+   \printdim/
+
+Le point essentiel est que
+
+\centrecode-\setbox<registre>=\hbox{\unhbox<registre>}-\idx*\unhbox
+
+\noindent redonne au \verb|<registre>| de boite les dimensions naturelles de la boite qu'il contient. La m\xE9thode donn\xE9e pour une boite horizontale est \xE9galement valable pour une boite verticale en rempla\xE7ant \idx\hbox par \idx\vbox ou \idx\vtop et \idx\unhbox par \idx\unvbox.\idx*[|)]{boite!redimensionnement}
+
+\subsection{Tester si un registre de boite est vide}\label{tester.boite.vide}\idx*[|(]{boite!registre!vide}
+Nous avons vu que le test \tidx{ifvoid}\verb|<registre>| est vrai si le registre de boite est vide. Il est tout de m\xEAme tr\xE8s important d'insister sur la diff\xE9rence entre un registre vide (c'est \xE0 dire ne contenant aucune boite) et un registre contenant une boite vide.
+
+Voici un exemple qui illustre le fait que si un registre contient une boite vide, il n'est pas vide !
+
+\showcode/\setbox0=\hbox{}% le registre 0 contient une boite vide\xA4\idx*\setbox\xA4
+Le registre \ifvoid0 est vide\else n'est pas vide\fi\xA4\tidx*{ifvoid}\xA4/
+
+D\xE8s lors se pose la question : \xAB comment tester si un registre de boite est vide ?\xBB La r\xE9ponse d\xE9pend de ce qu'on entend par \xAB vide \xBB. Le parall\xE8le devient \xE9vident avec un argument de macro qui n'\xE9tait pas \xAB vide \xBB s'il contenait une macro vide telle que \idx\empty (voir page~\pageref{argument.vide}). Pour r\xE9pondre \xE0 la question \xAB comment tester si un registre de boite est vide \xBB, nous allons construire un test purement d\xE9veloppable \xA7\ifzerodimbox de syntaxe
+
+\centrecode-\ifzerodimbox{<nombre>}{<code vrai>}{<code faux>}-
+
+qui renvoie \verb|<code vrai>| si le registre est vide ou s'il contient une boite dont toutes les dimensions sont nulles, et faux dans tous les autres cas.
+
+\showcode/\catcode`\@11
+\def\ifzerodimbox#1{% #1=registre de boite\xA4\xA7*\ifzerodimbox\xA4
+% revoie vrai si le registre est vide ou contient une boite de dimensions nulles
+	\csname% former la macro "\firstoftwo" ou "\secondoftwo"
+	\ifvoid#1first%% si le registre est vide "first"\xA4\tidx*{ifvoid}\xA4
+	\else% sinon
+		\ifdim\wd#1=\z@% si la largeur\xA4\idx*\wd\idx*\z@\xA4
+			\ifdim\ht#1=\z@% la hauteur\xA4\idx*\ht\xA4
+				\ifdim\dp#1=\z@ first% et la profondeur=0pt, "first"\xA4\idx*\dp\idx*\z@\xA4
+				\else second% dans les autres cas "second"
+				\fi
+			\else second%
+			\fi
+		\else second%
+		\fi
+	\fi
+	oftwo% compl\xE9ter avec "oftwo"
+	\endcsname
+}
+\catcode`\@12
+a) \setbox0=\hbox{}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par\xA4\idx*\setbox\tidx*{ifvoid}\xA4
+b) \box0 % affiche la boite vide, le registre est maintenant "void"
+   \ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+c) \setbox0=\hbox{x}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par\xA4\idx*\setbox\xA4
+d) \wd0=0pt \ht0=0pt \dp0=0pt % rend toutes les dimensions nulles
+   \ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par\xA4\idx*\setbox\xA4
+e) \setbox0=\vbox{}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\xA4\tidx*{ifvoid}\xA7*\ifzerodimbox\xA4/
+
+Le test est n\xE9gatif dans le cas c, seul cas o\xF9 le registre contient une boite de dimensions non nulles. Il est positif ailleurs, que la boite soit vide (cas a et e), que la boite soit non vide mais redimensionn\xE9e (cas d) ou que le registre soit vide (cas b).
+\grandsaut
+
+Le moteur \idx\eTeX{}\idx*{moteur!etex} nous donne une autre m\xE9thode, plus rapide et plus fiable pour tester si un registre de boite contient une boite \emph{vide}. Nous nous mettrons \xE0 l'abri du faux positif de l'exemple pr\xE9c\xE9dent (cas d) d'une boite non vide, mais redimensionn\xE9e pour que toutes ses dimensions soient nulles.
+
+La primitive \idx\lastnodetype de \idx\eTeX{} est de type registre d'entier et \xE0 tout moment, selon sa valeur qui varie de $-1$ \xE0 15, caract\xE9rise la nature du dernier n\oe ud compos\xE9. Les diff\xE9rents types sont expos\xE9s dans le manuel d'\idx\eTeX. Le type qui nous int\xE9resse ici est celui qui est qualifi\xE9 par l'entier $-1$ et qui caract\xE9rise un n\oe ud vide, c'est-\xE0-dire r\xE9sultant d'une liste vide.
+
+L'id\xE9e est donc de composer le contenu de la boite, et de tester hors de cette boite si \idx\lastnodetype est strictement n\xE9gatif, seul cas o\xF9 la boite sera vide. Nous allons mettre en \oe uvre cette m\xE9thode pour construire une macro \emph{non d\xE9veloppable} \xA7\ifvoidorempty de syntaxe
+
+\centrecode|\ifvoidorempty<registre>{<code vrai>}{<code faux>}|
+
+\noindent qui renverra \verb|<code vrai>| si le \verb|<registre>| est vide ou contient une boite vide :
+
+\showcode/\def\ifvoidorempty#1{% teste si le registre #1 est vide ou contient une boite vide\xA4\xA7*\ifvoidorempty\xA4
+	\ifvoid#1\relax\xA4\tidx*{ifvoid}\xA4
+		\expandafter\firstoftwo
+	\else
+		\begingroup% dans un groupe
+			\setbox0=% affecter \xE0 la boite 0\xA4\idx*\setbox\xA4
+				\ifhbox#1\hbox\bgroup\unhcopy% un boite horizontale\xA4\idx*\hbox\tidx*{ifhbox}\idx*\unhcopy\xA4
+				\else    \vbox\bgroup\unvcopy% ou verticale\xA4\idx*\vbox\idx*\unvcopy\xA4
+				\fi% dans laquelle on compose
+				#1\relax% #1 en dimensions naturelles
+				\expandafter\egroup% sauter la fin de la boite
+				\expandafter% et le \endgroup
+		\endgroup
+		\ifnum\lastnodetype=-1 % et tester si le dernier noeud est vide\xA4\idx*\lastnodetype\xA4
+			\expandafter\expandafter\expandafter\firstoftwo
+		\else
+			\expandafter\expandafter\expandafter\secondoftwo
+		\fi
+	\fi
+}
+a) \setbox0=\hbox{}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par\xA4\idx*\setbox\tidx*{ifvoid}\xA4
+b) \box0 % affiche la boite vide, le registre est maintenant "void"
+   \ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+c) \setbox0=\hbox{x}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par\xA4\idx*\setbox\xA4
+d) \wd0=0pt \ht0=0pt \dp0=0pt % rend toutes les dimensions nulles
+   \ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par\xA4\idx*\setbox\xA4
+e) \setbox0=\vbox{}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\xA4\tidx*{ifvoid}\idx*\setbox\xA7*\ifvoidorempty\xA4/\idx*[|)]{boite!registre!vide}
+
+\subsection{Mise en application}
+Comment pourrions-nous enfermer dans une boite \idx\vtop des \xE9l\xE9ments mis dans des \idx\hbox qui soient tous centr\xE9s horizontalement les uns par rapport aux autres ? Le but est d'\xE9crire
+
+\centrecode/\cvtop{Ligne du haut,Tr\xE8s grande ligne du milieu,Ligne du bas pour finir}/
+
+\noindent pour obtenir ceci
+
+\begin{centrage}
+\small
+texte avant...\vtop{\halign{\hfil#\hfil\cr
+Ligne du haut\cr Tr\xE8s grande ligne de milieu\cr Ligne de bas pour finir\crcr}}...texte apr\xE8s
+\end{centrage}
+
+Si nous empilons des \idx\hbox dans une \idx\vtop, nous ne pouvons pas centrer les \idx\hbox, car nous ne pouvons \xE9crire ni \idx\hfill ni \idx\hss dans une \idx\vtop puisque le mat\xE9riel y est vertical et que ces primitive, exclusivement horizontales, y sont interdites. Agir sur les ressorts de paragraphe \idx\leftskip et \idx\rightskip est sans effet puisque dans cette boite, \TeX{} ne compose pas de paragraphe, il ne fait qu'empiler des \idx\hbox verticalement.
+
+La solution va consister \xE0 trouver la longueur $l$ de la plus longue \idx\hbox, puis composer toutes les boites \idx\hbox avec une longueur impos\xE9e $l$ en ayant pris soin de centrer le contenu avec des ressorts \idx\hss plac\xE9s en d\xE9but et en fin de boite. La macro \verb|\doforeach| vue pr\xE9c\xE9demment nous sera d'un grand secours. La variable, que nous appelons \verb|\htext|, contiendra tout \xE0 tour \xE0 tour chaque \xE9l\xE9ment de la liste, mais il faudra proc\xE9der en deux passes successives :
+
+\begin{itemize}
+	\item la premi\xE8re trouvera, en les examinant tour \xE0 tour, la \idx\hbox la plus longue et cette dimension maximale sera stock\xE9e dans le registre de dimension \verb|\maxhsize|;
+	\item lors de la deuxi\xE8me passe, nous \xE9crirons \xE0 chaque it\xE9ration
+	
+	\centrecode-\hbox to\maxhsize{\hss\htext\hss}-
+	
+	pour enfermer l'\xE9l\xE9ment courant dans une \idx\hbox de longueur \verb|\maxhsize| et centr\xE9 dans celle-ci \xE0 l'aide des ressorts-primitives \idx\hss.
+\end{itemize}
+
+Pour tester si la longueur de l'\xE9l\xE9ment consid\xE9r\xE9 est plus grande que celle du pr\xE9c\xE9dent, il faut d'abord initialiser \verb|\hmaxsize| \xE0 la plus petite dimension permise qui est l'oppos\xE9 de la plus grande dimension \idx\maxdimen, registre de dimension d\xE9fini dans plain-\TeX{} et qui vaut \verb|16383.99999pt|. Ensuite, si la dimension de l'\xE9l\xE9ment est strictement sup\xE9rieure \xE0 \verb|\hmaxsize|, nous actualiserons \verb|\hmaxsize| \xE0 la longueur de l'\xE9l\xE9ment examin\xE9. En fin de boucle, nous serons assur\xE9s que \verb|\hmaxsize| est la plus grande longueur.\xA7*\cvtop[|(]
+
+\showcode|\newdimen\hmaxsize\xA4\idx*\newdimen\xA4
+\def\cvtop#1{%\xA4\xA7*\cvtop\xA4
+	\hmaxsize=-\maxdimen% initialise \xE0 la plus petite longueur\xA4\idx*\maxdimen\xA4
+	\doforeach\htext\in{#1}% pour chaque \xE9l\xE9ment :\xA4\xA7*\doforeach\xA4
+		{\setbox0=\hbox{\htext}% stocker l'\xE9l\xE9ment "\htext" dans une \hbox\xA4\idx*\hbox\idx*\setbox\xA4
+		\ifdim\wd0 >\hmaxsize% si sa longueur est sup\xE9rieure \xE0 \hmaxsize\xA4\tidx*{ifdim}\xA4
+			\hmaxsize=\wd0 % mettre \xE0 jour \hmaxsize\xA4\idx*\wd\xA4
+		\fi
+		}%
+	\vtop{% dans une \vtop...\xA4\idx*\vtop\xA4
+		\doforeach\htext\in{#1}% pour chaque \xE9l\xE9ment :\xA4\xA7*\doforeach\xA4
+			{\hbox to\hmaxsize{\hss\htext\hss}% le centrer dans une \hbox de longueur \hmaxsize\xA4\idx*\hss\xA4
+			}%
+	}%
+}
+
+texte avant...\cvtop{Ligne du haut,Tr\xE8s grande ligne du milieu,Ligne du bas pour finir}%
+...texte apr\xE8s|
+
+\begin{exercice}
+Proposer une autre fa\xE7on de faire sans enfermer \verb|\htext| dans une \idx\hbox.
+\solution
+Chaque \xE9l\xE9ment peut \xEAtre compos\xE9 comme un paragraphe. Pour cela, la longueur de la \idx\vtop doit \xEAtre \xE9gale \xE0 \verb|\hmaxsize|, l'indentation doit \xEAtre nulle et pour que les paragraphes soient centr\xE9s, \idx\leftskip et \idx\rightskip sont rendus \xE9gaux \xE0 \texttt{0pt plus 1fil}.
+
+Cela donne :
+
+\showcode|\newdimen\hmaxsize\xA4\idx*\newdimen\xA4
+\def\cvtop#1{%\xA4\xA7*\cvtop\xA4
+	\hmaxsize=-\maxdimen% initialise \xE0 la plus petite longueur\xA4\idx*\maxdimen\xA4
+	\doforeach\htext\in{#1}% pour chaque \xE9l\xE9ment :\xA4\xA7*\doforeach\xA4
+		{\setbox0=\hbox{\htext}% stocker l'\xE9l\xE9ment "\htext" dans une \hbox\xA4\idx*\hbox\idx*\setbox\xA4
+		\ifdim\wd0 >\hmaxsize% si sa longueur est sup\xE9rieure \xE0 \hmaxsize\xA4\tidx*{ifdim}\xA4
+			\hmaxsize=\wd0 % mettre \xE0 jour \hmaxsize\xA4\idx*\wd\xA4
+		\fi
+		}%
+	\vtop{% dans une \vtop...\xA4\idx*\vtop\xA4
+		\hsize\hmaxsize % longueur de la \vtop = \maxhsize
+		\parindent=0pt % pas d'indentation\xA4\idx*\parindent\xA4
+		\leftskip=0pt plus1fil minus0pt \rightskip=\leftskip% ressorts de centrage\xA4\idx*\leftskip\idx*\rightskip\xA4
+		\doforeach\htext\in{#1}% pour chaque \xE9l\xE9ment :\xA4\xA7*\doforeach\xA4
+			{\htext\par}% le composer et finir le paragraphe
+	}%
+}
+
+texte avant...\cvtop{Ligne du haut,Tr\xE8s grande ligne du milieu,Ligne du bas pour finir}%
+...texte apr\xE8s|\xA7*\cvtop[|)]
+\end{exercice}
+
+Ces fa\xE7ons de faire sont un peu tir\xE9e par les cheveux. En effet, nous venons de programmer ce que fait (entre autres) la primitive de \TeX{} \xAB \idx\halign\verb|{<code>}| \xBB. Le but ici n'est pas d'en d\xE9crire toutes ses fonctionnalit\xE9s, car elles sont tr\xE8s nombreuses et pour certaines, tr\xE8s techniques\footnote{Pour en savoir plus, il est sage de se tourner vers le \TeX book, chapitre 22.}.
+
+Pour aller \xE0 l'essentiel, cette primitive op\xE8re en mode vertical\idx*{mode!vertical} et construit des alignements (autrement dit, des tableaux) constitu\xE9s de lignes, elles-m\xEAmes partag\xE9es en cellules. Ce qui est remarquable, c'est que lorsque \idx\halign lit son argument, elle compose \emph{tous} les contenus des cellules et par cons\xE9quent, fixe comme longueur d'une colonne la plus grande des longueurs rencontr\xE9es dans cette colonne.
+
+Du c\xF4t\xE9 de la syntaxe, chaque ligne s'ach\xE8ve par la primitive \idx\cr et il est prudent de placer \idx\crcr en fin de tableau. Au sein d'une ligne, le token  \xAB\verb|&|\xBB (de catcode \number\catcode`\&) signifie \xAB passer \xE0 la colonne suivante\xBB. La syntaxe d'une ligne est donc :
+
+\centrecode-<cellule 1>&<cellule 2>& ... &<cellule n>\cr-
+
+Raffinement suppl\xE9mentaire, il est possible pour toutes les cellules d'une m\xEAme colonne de d\xE9finir un code qui sera ins\xE9r\xE9 avant leur contenu et un code qui sera ins\xE9r\xE9 apr\xE8s. Pour cela, la primitive \idx\halign admet un \emph{pr\xE9ambule} qui est plac\xE9 avant le premier \idx\cr. La syntaxe de ce pr\xE9ambule reprend la syntaxe d'une ligne, mais le \verb|<contenu>| d'une cellule est symbolis\xE9 par le token \xAB\cidx\#\xBB. Ainsi, pour une colonne (c'est-\xE0-dire compris entre deux \xAB\cidx[ (caract\xE8re d'alignement)]\&\xBB), si on \xE9crit dans le pr\xE9ambule
+
+\centrecode-<code avant>#<code apr\xE8s>-
+
+\noindent alors, le texte \verb|<code avant>| sera ins\xE9r\xE9 avant le code contenu dans les cellules et \verb|<code apr\xE8s>| sera ins\xE9r\xE9 apr\xE8s.
+
+Dans l'exemple ci-dessous, la colonne \no1 est d\xE9finie pour que \xAB\verb|X|\xBB soit affich\xE9 avant chaque cellule et \xAB\verb|**\ignorespaces|\xBB apr\xE8s, o\xF9 \idx\ignorespaces nous assure qu'en dehors du pr\xE9ambule, les espaces ins\xE9r\xE9s avant le premier \verb|&| ne compteront pas. Pour la deuxi\xE8me colonne, \cidx\# est seul et donc les cellules de cette colonne seront compos\xE9es sans aucun ajout. Enfin, la colonne \no3 est compos\xE9e au fer \xE0 droite en ins\xE9rant \idx\hfil \xE0 gauche de \cidx\# :
+
+\showcode/\halign{X#**\ignorespaces&#&\hfil #\cr % pr\xE9ambule\xA4\idx*\halign\idx*\ignorespaces\xA4
+foo            &foo bar&123 456\cr % premi\xE8re ligne\xA4\idx*\cr\xA4
+deuxi\xE8me ligne &1      &12\cr % deuxi\xE8me ligne
+a              &\TeX   &1 2 3 4 5 6\cr % troisi\xE8me ligne
+\crcr}\xA4\idx*\crcr\xA4/
+
+Pour tirer parti de \idx\halign dans le code de \xA7\cvtop[|(], nous allons d\xE9finir un alignement \xE0 une colonne et nous sp\xE9cifierons \xAB\idx\hfil{}\cidx\#{}\idx\hfil\xBB en pr\xE9ambule afin que les contenus soient centr\xE9s. \xC0 l'aide de \xA7\substtocs, nous stockerons dans une macro \verb|\temp| l'argument de \xA7\cvtop o\xF9 les virgules auront \xE9t\xE9 remplac\xE9es par \idx\cr. Il suffira ensuite de placer la macro \verb|\temp| juste apr\xE8s le \idx\cr qui marque la fin du pr\xE9ambule pour que \TeX{} la d\xE9veloppe (car le d\xE9but de chaque cellule est d\xE9velopp\xE9) pour constituer le corps du tableau :
+
+\showcode|\def\cvtop#1{%\xA4\xA7*\cvtop\xA4
+	\vtop{% \vtop assure que l'on est en mode vertical\xA4\idx*\vtop\idx*{mode!vertical}\xA4
+		\substtocs\temp{#1}{,}{\cr}% dans \temp, remplacer les "," par "\cr"\xA4\xA7\substtocs\idx*\cr\xA4
+		\halign{%\xA4\idx*\halign\xA4
+			\hfil##\hfil\cr% pr\xE9ambule : centrer le contenu\xA4\idx*\hfil\xA4
+			\temp\crcr}% mettre \temp dans l'alignement\xA4\idx*\crcr\xA4
+	}% \temp est d\xE9truite en sortant de la boite
+}
+
+texte avant...\cvtop{Ligne du haut,Tr\xE8s grande ligne du milieu,Ligne du bas pour finir}%
+...texte apr\xE8s|
+
+Ce code en sugg\xE8re un autre, capable de calculer \xE0 l'aide de \idx\halign, la plus grande longueur de textes. Pour cela, la macro \xA7\calcmaxdim, de syntaxe
+
+\centrecode-\calcmaxdim\<macro>{<texte 1>,texte 2>,...,<texte n>}-
+
+\noindent stockera dans la \verb|\<macro>| la plus grande longueur des \verb|<texte>|.
+
+\showcode/\def\calcmaxdim#1#2{%\xA4\xA7*\calcmaxdim\xA4
+	\setbox0=\vtop{% \vtop assure que l'on est en mode vertical (interne)\xA4\idx*\vtop\idx*\setbox\xA4
+		\substtocs\temp{#2}{,}{\cr}% dans \temp, remplacer les "," par "\cr"\xA4\xA7*\substtocs\idx*\cr\xA4
+		\halign{##\hfil\cr% pr\xE9ambule : composer au fer \xE0 gauche\xA4\idx*\halign\idx*\hfil\xA4
+			\temp\crcr}% mettre \temp dans l'alignement\xA4\idx*\crcr\xA4
+	}% \temp est d\xE9truite en sortant de la boite
+	\edef#1{\the\wd0 }%\xA4\idx*\the\idx*\wd\xA4
+}
+a) La plus grande longueur vaut
+   \calcmaxdim\foo{Ligne du haut,Tr\xE8s grande ligne du milieu,Ligne du bas pour finir}\foo
+
+b) V\xE9rification : \setbox0=\hbox{Tr\xE8s grande ligne du milieu}\the\wd0 \xA4\idx*\setbox\idx*\the\idx*\wd\xA4/\xA7*\cvtop[|)]\idx*[|)]{boite}
+
+\section{Les r\xE9glures}\idx*[|(]{r\xE9glure}
+\subsection{Tracer des lignes}
+Nous allons maintenant nous int\xE9resser \xE0 des boites un peu particuli\xE8res, les boites de r\xE9glure ou \xABr\xE9glures\xBB, c'est-\xE0-dire des boites enti\xE8rement remplies de noir.
+
+\begin{regle}
+Les primitives \idx\hrule et \idx\vrule, qui op\xE8rent respectivement en \idx*{mode!vertical}mode \emph{vertical} et \emph{horizontal}\idx*{mode!horizontal}, tracent des r\xE9glures. Par d\xE9faut, les dimensions de ces r\xE9glures sont :
+
+\begin{centrage}
+	\small
+	\begin{tabular}{rcc}\hline
+		&\idx\hrule&\idx\vrule\\\hline
+		largeur (width) & \verb|*| & 0.4pt\\
+		hauteur (height)& 0.4pt&\verb|*|\\
+		profondeur (depth)&0pt&\verb|*|\\\hline
+	\end{tabular}
+\end{centrage}
+
+L'\xE9toile signifie que la dimension est celle de la boite qui contient la r\xE9glure.
+
+Si l'on souhaite passer outre les valeurs par d\xE9faut et imposer une ou plusieurs dimensions, on doit faire suivre ces deux primitives  d'un (ou plusieurs) mots-cl\xE9s parmi \xAB\verb|width|\xBB, \xAB\verb|height|\xBB ou \xAB\verb|depth|\xBB et en respectant cet ordre. S'ils sont pr\xE9sents, ces mots-cl\xE9s doivent \xEAtre suivis de la \verb|<dimension>| que l'on souhaite imposer.
+
+Si plusieurs sp\xE9cifications contradictoires sur une dimension sont sp\xE9cifi\xE9es, la derni\xE8re est prise en compte.
+\end{regle}
+
+Voici par exemple ce que l'on obtient si on \xE9crit \xAB\idx\vrule\xBB dans le code source imm\xE9diatement apr\xE8s ces deux points :\vrule. On constate que la r\xE9glure, qui op\xE8re en mode horizontal, a la largeur par d\xE9faut de \verb|0.4pt| et a pour hauteur et profondeur celles de la boite dans laquelle elle est enferm\xE9e. Cette boite est la ligne en cours de composition.
+
+Passons maintenant \xE0 \idx\hrule et voici l'effet de \xAB\idx\hrule\xBB juste apr\xE8s ces deux points :\hrule
+La r\xE9glure prend la totalit\xE9 de la largeur de la boite qui la contient. La boite dont il est question dans ce cas est la page elle-m\xEAme, de largeur \idx\hsize, dans laquelle les \xE9l\xE9ments sont empil\xE9s verticalement. On remarque que pour satisfaire son mode de fonctionnement, \idx\hrule passe en mode vertical\idx*{mode!vertical}. Puisque nous \xE9tions \xE0 l'int\xE9rieur d'un paragraphe, celui-ci a \xE9t\xE9 compos\xE9 avant le passage en mode vertical. Par ailleurs, le \idx{ressort d'interligne} n'est pas ins\xE9r\xE9, ni avant la r\xE9glure ni apr\xE8s. Une r\xE9glure \idx\hrule est donc dessin\xE9e \emph{au plus pr\xE8s} verticalement de ce qui la suit et de ce qui la pr\xE9c\xE8de.
+
+L'exemple suivant montre que les primitives de r\xE9glures utilis\xE9es sans mot-cl\xE9 adaptent leurs dimensions \xE0 celles de la boite qui les contient. Ici, on dessine des \idx\hrule au sommet et au bas d'une \idx\vbox dans la premi\xE8re ligne alors que l'on trace des \idx\vrule avant et apr\xE8s une \idx\vtop \xE0 la deuxi\xE8me ligne :
+
+\showcode/a) .......\vbox{\hrule\hbox{foo}\hbox{ligne du bas}\hrule}.......\medbreak\xA4\idx*\vbox\idx*\hrule\idx*\hbox\xA4
+b) .......\vrule\vtop{\hbox{foo}\hbox{ligne du bas}}\vrule.......\xA4\idx*\vtop\idx*\vrule\xA4/
+
+On voit clairement au cas a que les \idx\hrule \xE0 l'int\xE9rieur de \idx\vbox prennent chacune la largeur totale de la boite. En ce qui concerne les \idx\vrule qui se trouvent avant et apr\xE8s la \idx\vtop au cas b, elles ont adapt\xE9 leur profondeur et hauteur pour s'\xE9tendre sur la hauteur totale de la boite qui ici est la ligne en cours.
+
+Voici maintenant des r\xE9glures dont les dimensions sont impos\xE9es par mots-cl\xE9s :
+
+\showcode/Une r\xE9glure de 1.5cm :\hrule width1.5cm
+foo\vrule width 2pt height .5cm depth .2cm bar/
+
+Ici encore, la \idx\vrule est en contact avec la \idx\hrule puisque le \idx{ressort d'interligne} n'est pas ins\xE9r\xE9.
+
+\begin{exercice}
+\xC9crire une macro \xA7\showdim[|(], op\xE9rant en mode horizontal\idx*{mode!horizontal}, dont l'argument est une dimension et qui repr\xE9sente sous forme d'une r\xE9glure horizontale la dimension donn\xE9e.
+
+Par exemple, \xAB\xA7\showdim\verb-{1.5cm}-\xBB produit \xAB\showdim{1.5cm}\xBB o\xF9 les traits verticaux de d\xE9but et de fin ont une hauteur de \verb|1ex|. Toutes les r\xE9glures ont une \xE9paisseur de \verb|0.4pt|.
+
+\solution
+Voici le code de cette macro :
+
+\showcode/\def\showdim#1{%\xA4\xA7*\showdim\xA4
+	\vrule width 0.4pt height 1ex  depth 0pt % trait vertical gauche\xA4\idx*\vrule\defline\aaa\xA4
+	\vrule width #1    height0.4pt depth 0pt % r\xE9glure horizontale de longueur #1\xA4\defline\bbb\xA4
+	\vrule width 0.4pt height 1ex  depth 0pt % trait vertical droit\xA4\idx*\vrule\defline\ccc\xA4
+	\relax% stoppe la lecture de la pr\xE9c\xE9dente dimension
+}
+
+a) une longueur de 1 cm : \showdim{1cm}\par
+b) une longueur de 137,4 pt : \showdim{137,4pt}\par
+c) une longueur de 2 mm : \showdim{2mm}/
+
+Le code est tr\xE8s simple. En premier lieu (ligne \no\aaa), la primitive \idx\vrule qui op\xE8re en mode horizontal\idx*{mode!horizontal} trace une barre verticale d'\verb|1ex| de hauteur et de \verb|0.4pt| d'\xE9paisseur. Ensuite, \xE0 la ligne \no\bbb, nous la faisons suivre d'une ligne horizontale dont la longueur a \xE9t\xE9 forc\xE9e \xE0 la dimension contenue dans l'argument et dont la hauteur est \verb|0.4pt|. Nous finissons \xE0 la ligne \no\ccc{} avec la m\xEAme barre verticale qu'au d\xE9but.\xA7*\showdim[|)]
+\end{exercice}
+
+\subsection{Encadrer}\idx*[|(]{encadrer}
+On commence \xE0 deviner qu'il serait assez facile de programmer une macro \xA7\FRbox qui encadre tout ce qui est dans son argument, argument devant \xEAtre compos\xE9 en mode horizontal\idx*{mode!horizontal} :
+
+\centrecode|\FRbox{<contenu>}|\xA7*\FRbox
+
+Les deux param\xE8tres importants pour l'aspect visuel sont l'\xE9paisseur des r\xE9glures et l'espacement entre elles et le contenu. Chacun de ces param\xE8tres sera un registre de dimension; \xA7\frboxrule pour l'\xE9paisseur et \xA7\frboxsep pour l'espacement\footnote{Ne pas confondre les noms de ces registres avec \texttt{\string\fboxrule} et \texttt{\string\fboxsep} qui sont les registres d\xE9finis par \LaTeX{} pour les boites encadr\xE9es avec la macro \texttt{\string\fbox}.}.
+
+En ce qui concerne la m\xE9thode pour encadrer un contenu arbitraire, il y a deux fa\xE7ons diff\xE9rentes de tracer les r\xE9glures :
+
+\begin{centrage}
+	\leavevmode
+	\frboxrule=0.2pt \frboxsep=1pt
+	\small
+	\vbox{%
+		\offinterlineskip
+		\hbox{\FRbox{\vrule height 1mm width\dimexpr2.2cm+2\frboxsep+2\frboxrule}}%
+		\hbox{%
+			\FRbox{\vrule width1mm height\dimexpr1cm-2\frboxsep-2\frboxrule }%
+			\vbox to1cm{\vss\hbox to2cm{\hss\verb|<contenu>|\hss}\vss}%
+			\FRbox{\vrule width1mm height\dimexpr1cm-2\frboxsep-2\frboxrule }%
+			}%
+		\hbox{\FRbox{\vrule height 1mm width\dimexpr2.2cm+2\frboxsep+2\frboxrule}}%
+	}\hskip0pt plus1fil
+	\hbox{%
+		\FRbox{\vrule width1mm height\dimexpr1.2cm+2\frboxsep+2\frboxrule }%
+		\vbox to\dimexpr1.2cm+4\frboxsep+4\frboxrule{%
+			\hbox{\FRbox{\vrule height1mm width\dimexpr2cm-2\frboxsep-2\frboxrule }}%
+			\vskip 0pt plus 1fil
+			\hbox to2cm{\hss \verb|<contenu>|\hss}%
+			\vskip 0pt plus 1fil
+			\hbox{\FRbox{\vrule height1mm width\dimexpr2cm-2\frboxsep-2\frboxrule }}%
+		}%
+		\FRbox{\vrule width1mm height\dimexpr1.2cm+2\frboxsep+2\frboxrule }%
+	}%
+\end{centrage}
+
+\noindent D\xE9cidons-nous par exemple pour la structure de droite. Pour arriver \xE0 nos fins, nous allons construire une \idx\vbox dans laquelle nous allons ins\xE9rer, de haut en bas :
+
+\begin{itemize}
+	\item une r\xE9glure horizontale ;
+	\item une espace verticale \xE9gale \xE0 \xA7\frboxsep ;
+	\item le contenu (pr\xE9c\xE9d\xE9 et suivi d'espaces \xE9gales \xE0 \xA7\frboxsep);
+	\item une espace verticale \xE9gale \xE0 \xA7\frboxsep ;
+	\item une r\xE9glure horizontale.
+\end{itemize}
+
+\noindent Nous obtiendrons donc :
+
+\begin{centrage}
+	\leavevmode
+	\small
+	\frboxrule=0.2pt \frboxsep=1pt
+	\hbox{%
+		\vbox to\dimexpr1.2cm+4\frboxsep+4\frboxrule{%
+			\hbox{\FRbox{\vrule height1mm width\dimexpr2cm-2\frboxsep-2\frboxrule }}%
+			\vskip 0pt plus 1fil
+			\hbox to2cm{\hss\verb|<contenu>|\hss}%
+			\vskip 0pt plus 1fil
+			\hbox{\FRbox{\vrule height1mm width\dimexpr2cm-2\frboxsep-2\frboxrule }}%
+		}%
+	}%
+\end{centrage}
+
+\Qu 'ils soient horizontaux ou verticaux, tous les espaces seront ins\xE9r\xE9s avec la primitive \idx\kern qui agit selon le mode en cours. Voici la construction obtenue pour un contenu \xE9gal au mot \xAB Programmation \xBB :
+
+\showcode/\xA4\verb-\newdimen\frboxrule \newdimen\frboxsep-\idx*\newdimen\xA7*\frboxrule\xA7*\frboxsep\xA4
+\frboxsep=5pt \frboxrule=1pt \xA4\xA7*\frboxsep \xA7*\frboxrule\xA4
+\leavevmode\xA4\idx*\leavevmode\xA4
+...%
+\vbox{%\xA4\idx*\vbox\xA4
+	\hrule height\frboxrule% r\xE9glure sup\xE9rieure\xA4\idx*\hrule\xA4
+	\kern\frboxsep% espace verticale haute\xA4\idx*\kern\xA4
+	\hbox{\kern\frboxsep Programmation\kern\frboxsep}% contenu + espaces horizontales\xA4\idx*\hbox\xA4
+	\kern\frboxsep% espace verticale basse\xA4\xA7*\frboxsep\xA4
+	\hrule height\frboxrule% r\xE9glure inf\xE9rieure\xA4\xA7*\frboxrule\xA4
+	}%
+.../
+
+\noindent Il ne reste plus qu'\xE0 envelopper le tout dans une boite horizontale \idx\hbox, apr\xE8s avoir fait pr\xE9c\xE9der la \idx\vbox de \idx\vrule qui seront les r\xE9glures verticales \xE0 droite et \xE0 gauche de l'encadrement\xA7*\FRbox :
+
+\showcode|\xA4\verb-\newdimen\frboxrule \newdimen\frboxsep-\idx*\newdimen\xA7*\frboxrule\xA7*\frboxsep\xA4
+\frboxsep=5pt \frboxrule=0.6pt
+\def\FRbox#1{% /!\ ne change pas le mode H ou V en cours\xA4\xA7*\FRbox\xA4
+	\hbox{% mettre \xE0 la suite horizontalement les 3 choses suivantes :\xA4\idx*\hbox\xA4
+		\vrule width\frboxrule% 1) r\xE9glure gauche\xA4\idx*\vrule\xA4
+		\vbox{%                 2) un empilement vertical comprenant\xA4\idx*\vbox\xA4
+			\hrule height\frboxrule% a) r\xE9glure sup\xE9rieure\xA4\idx*\hrule \xA4
+			\kern\frboxsep%          b) espace verticale haute\xA4\idx*\kern \xA4
+			\hbox{%                  c) contenu + espaces en mode H
+				\kern\frboxsep#1\kern\frboxsep\xA4\defline\ccc\xA4
+			}%
+			\kern\frboxsep%          d) espace verticale basse\xA4\defline\aaa\xA7*\frboxsep\xA4
+			\hrule height\frboxrule% e)r\xE9glure inf\xE9rieure\xA4\defline\bbb\xA4
+			}%
+		\vrule width\frboxrule% 3) r\xE9glure droite\xA4\idx*\vrule\xA7*\frboxrule\xA4
+	}%
+}
+Ligne de base : ...\FRbox{Programmation}...%
+\frboxrule=2pt \FRbox{Programmation}...%
+\frboxsep=0pt \FRbox{Programmation}...%
+\frboxrule0.4pt \FRbox{Programmation}...\xA4\xA7*\FRbox\xA4|
+
+On constate que la \idx{ligne de base} du contenu des boites n'est pas align\xE9e avec la \idx{ligne de base} de la ligne en cours. En fait, comme la \idx\vbox empile les \xE9l\xE9ments au-dessus de la \idx{ligne de base} du dernier \xE9l\xE9ment, le \idx{point de r\xE9f\xE9rence} de la \idx\vbox se trouve sur la \idx{ligne de base} de la r\xE9glure inf\xE9rieure trac\xE9e \xE0 la ligne \no\bbb, c'est-\xE0-dire au niveau du bord \emph{inf\xE9rieur} de cette r\xE9glure\footnote{Si nous avions \xE9crit \texttt{depth} au lieu de \texttt{height} \xE0 la ligne \no\bbb, le point de r\xE9f\xE9rence aurait \xE9t\xE9 au niveau du bord \emph{sup\xE9rieur} de la r\xE9glure du bas.}. Le probl\xE8me qui se pose est le suivant : comment construire une boite verticale o\xF9 l'on place des listes de mat\xE9riels verticaux
+
+\centrecode-<liste a>
+<liste b>-
+
+\noindent et faire en sorte que le \idx{point de r\xE9f\xE9rence} de la boite ainsi construite soit sur la \idx{ligne de base} du dernier \xE9l\xE9ment vertical de \verb|<liste a>| ? Faire appel \xE0 \idx\vbox ou \idx\vtop seules ne peut convenir. Il fait \emph{combiner} ces deux boites. L'id\xE9e est d'enfermer \verb|<liste a>| dans une \idx\vbox et mettre cette \idx\vbox comme premier \xE9l\xE9ment vertical d'une \idx\vtop qui englobe le tout. La boite ainsi construite a la structure suivante\label{frbox.ligne.de.base} :
+
+\centrecode-\vtop{%\xA4\idx*\vtop\xA4
+	\vbox{<liste a>}
+	<liste b>
+}-
+
+De par les d\xE9finitions de \idx\vbox et \idx\vtop, le \idx{point de r\xE9f\xE9rence} de la boite externe \idx\vtop se trouvera sur la \idx{ligne de base} du dernier \xE9l\xE9ment vertical de \verb|<liste a>|. Voici un exemple qui illustre cette manipulation :
+
+\showcode/Persuadez-vous que :
+\vtop{\xA4\idx*\vtop\xA4
+	\vbox{\xA4\idx*\vbox\xA4
+		\hbox{Programmer}\xA4\idx*\hbox\xA4
+		\hbox{en}
+		\hbox{\TeX}
+		\hbox{est}% <- ligne de base de la \vtop
+	}
+	\hbox{\it tout sauf}\xA4\idx*\it\xA4
+	\hbox{facile.}
+}/
+
+Nous allons appliquer cette structure pour cr\xE9er une nouvelle macro \xA7\frbox[|(] afin que, contrairement \xE0 \xA7\FRbox, le point de r\xE9f\xE9rence du cadre soit au niveau de la \idx{ligne de base} du contenu. Il faut donc rejeter hors de la \idx\vbox les mat\xE9riels verticaux des lignes \nos\aaa{} et \bbb{} :
+
+\showcode/%\newdimen\frboxrule \newdimen\frboxsep
+\frboxrule=0.4pt \frboxsep=2pt
+\def\frbox#1{% ne pas changer le mode H ou V en cours\xA4\xA7*\frbox\xA4
+	\hbox{% enferme dans une \hbox\xA4\idx*\hbox\xA4
+		\vrule width\frboxrule% r\xE9glure gauche\xA4\idx*\vrule\xA7*\frboxrule\xA4
+		\vtop{%\xA4\idx*\vtop\xA4
+			\vbox{% 1er \xE9l\xE9ment de la \vtop\xA4\idx*\vbox\xA4
+				\hrule height\frboxrule% r\xE9glure sup\xE9rieure\xA4\idx*\hrule\xA4
+				\kern\frboxsep% espace haut\xA4\idx*\kern\xA4
+				\hbox{%\xA4\idx*\hbox\xA4
+					\kern\frboxsep% espace gauche
+					#1% contenu
+					\kern\frboxsep% espace droite\xA4 \xA7*\frboxsep\xA4
+					}%
+			}% puis autres \xE9l\xE9ments de la \vtop, sous la ligne de base
+			\kern\frboxsep% espace bas
+			\hrule height\frboxrule% r\xE9glure inf\xE9rieure
+		}%
+		\vrule width\frboxrule% r\xE9glure droite\xA4\idx*\vrule \xA7*\frboxrule\xA4
+	}%
+}
+Ligne de base : ......\frbox{Programmation}......%
+\frboxrule=2pt \frbox{Programmation}......%
+\frboxsep=0pt \frbox{Programmation}......%
+\frboxrule0.4pt \frbox{Programmation}......\xA4\xA7*\frbox\xA4/
+
+\begin{exercice}
+Cr\xE9er une macro \xA7\centretitre\verb|{<texte>}| dont l'argument doit \xEAtre compos\xE9 dans un cadre (via \xA7\frbox) qui prend toute la largeur de composition, c'est-\xE0-dire \idx\hsize. L'argument doit \xEAtre centr\xE9 dans ce cadre.
+\solution
+Tout d'abord, nous allons placer en d\xE9but de macro un \verb|\medbreak| ce qui aura pour effet de composer le paragraphe en cours si la macro est appel\xE9e en mode horizontal\idx*{mode!horizontal} et sautera une espace verticale. Ensuite, la primitive \idx\noindent interdira le placement de la boite d'indentation en d\xE9but de paragraphe, et provoquera le passage en mode horizontal\idx*{mode!horizontal}.
+
+Nous allons composer le \verb|<texte>| dans une boite verticale \idx\vbox. Sa dimension horizontale, sp\xE9cifi\xE9e par \idx\hsize, doit tenir compte des r\xE9glures droite et gauche (chacune de dimension \xA7\frboxrule) ainsi que les espaces \xE0 droite et \xE0 gauche entre le \verb|<texte>| et les r\xE9glures (chacun de dimension \xA7\frboxsep). La dimension horizontale de la boite sera donc
+
+\begin{centrage}
+	\small$\hbox{\verb|\hsize|}-2\hbox{\xA7\frboxrule}-2\hbox{\xA7\frboxrule}$\idx*\hsize
+\end{centrage}
+
+Pour que le centrage soit effectif, nous jouerons sur les ressorts \idx\leftskip et \idx\rightskip sans oublier d'annuler le ressort de fin de paragraphe\idx*{paragraphe!centrage} \idx\parfillskip.
+
+\showcode/\def\centretitre#1{%\xA4\xA7*\centretitre\xA4
+	\medbreak% passe en mode v puis saute une espace verticale\xA4\idx*\medbreak\xA4
+	\noindent% pas d'indentation et passe en mode horizontal\xA4\idx*\noindent\idx*{mode!horizontal}\xA4
+	\frbox{% encadre\xA4\xA7*\frbox\xA4
+		\vbox{% une boite verticale\xA4\idx*\vbox\xA4
+			\hsize=\dimexpr\hsize-2\frboxrule-2\frboxsep\relax\xA4\idx*\hsize\idx*\dimexpr \xA7*\frboxsep \xA7*\frboxrule\xA4
+			\parindent=0pt % pas d'indentation\xA4\idx*\parindent\xA4
+			\leftskip=0pt plus1fil \rightskip=\leftskip% ressorts de centrage\xA4\idx*\leftskip\idx*\rightskip\xA4
+			\parfillskip=0pt % annule le ressort de fin de paragraphe\xA4\idx*\parfillskip\xA4
+			#1% ins\xE8re le titre
+			\endgraf% et le compose\xA4\idx*\endgraf\xA4
+			}%
+	}%
+	\medbreak% passe en mode v puis saute une espace verticale\xA4\idx*\medbreak\xA4
+	\ignorespaces% mange les espaces situ\xE9s apr\xE8s la macro \centretitre\xA4\idx*\ignorespaces\xA4
+}
+\frboxrule=0.8pt \frboxsep=5pt
+Voici un
+\centretitre{Titre}
+puis un
+\centretitre{Texte tr\xE8s long pour composer un titre qui va prendre plusieurs
+lignes et pour s'assurer que la composition s'effectue correctement}\xA4\xA7*\centretitre\xA4/
+\end{exercice}\xA7*\frbox[|)]\idx*[|)]{encadrer}
+
+\idx*[|(]{souligner}\begin{exercice}
+Programmer une macro \xA7\souligne\verb|{<texte>}| qui souligne d'un trait de 0.4pt d'\xE9paisseur le \verb|<texte>|. Le trait de soulignement devra se situer \xE0 \verb|1pt| au-dessous du \verb|<texte>| :
+
+\begin{centrage}
+\small
+\begin{tabular}{>{\ttfamily\hfill}r<{\kern1.5em \normalfont affiche\kern1.5em}@{}l}
+\string\souligne\{Du texte\}&\souligne{Du texte}\\
+\string\souligne\{Du texte profond\}&\souligne{Du texte profond}
+\end{tabular}
+\end{centrage}
+
+Proposer une variante \xA7\Souligne o\xF9 le trait devra se situer \xE0 1pt au-dessous de la \idx{ligne de base}, quelle que soit la profondeur du texte \xE0 souligner :
+
+\begin{centrage}
+\small
+\begin{tabular}{>{\ttfamily\hfill}r<{\kern1.5em \normalfont affiche\kern1.5em}@{}l}
+\string\Souligne\{Du texte\}&\Souligne{Du texte}\\
+\string\Souligne\{Du texte profond\}&\Souligne{Du texte profond}
+\end{tabular}
+\end{centrage}
+
+\solution
+Nous devons tracer une r\xE9glure ayant comme dimension horizontale celle de la \idx\hbox dans laquelle est plac\xE9 l'argument. Afin de pouvoir mesurer cette boite, nous allons stocker \verb|\hbox{#1}| dans le registre de boite \no0\idx*{boite!\no0}.
+
+Mais avant de poursuivre, regardons d'un peu plus pr\xE8s les dimensions qui suivent les mots-cl\xE9s \verb|height|, \verb|width| et \verb|depth|, et consid\xE9rons-les comme des dimensions \emph{sign\xE9es}. Car c'est ainsi que \TeX{} travaille; rien ne dit qu'une dimension, f\xFBt-elle de r\xE9glure, doit \xEAtre positive ! Par exemple, pour tracer une r\xE9glure de \verb|0.4pt| d'\xE9paisseur \xE0 \verb|10pt| de hauteur, nous pouvons fixer sa hauteur \xE0 \verb|10.4pt| et sa profondeur \xE0 \verb|-10pt| :
+
+\showcode/Une r\xE9glure en hauteur : \vrule width 1cm height 10.4pt depth -10pt \xA4\idx*\vrule\xA4/
+
+De m\xEAme, pour tracer une r\xE9glure d'\xE9paisseur \verb|0.4pt| \xE0 \verb|2pt| sous la \idx{ligne de base}, il suffit de fixer sa profondeur \xE0 \verb|2.4pt| et sa hauteur \xE0 \verb|-2pt| :
+
+\showcode/Une r\xE9glure en dessous: \vrule width 1cm depth 2.4pt height -2pt \xA4\idx*\vrule\xA4/
+
+Revenons \xE0 notre probl\xE8me\ldots{} Nous stockerons la \idx\hbox dans le registre de boite \no0\idx*{boite!\no0}. Puis, nous allons appliquer l'astuce expos\xE9e ci-dessus pour tracer une r\xE9glure de \verb|0.4pt| d'\xE9paisseur \xE0 une distance de \verb|\dp0+1pt| sous la \idx{ligne de base}. Pour cela, nous allons stocker dans ce m\xEAme registre \no0\idx*{boite!\no0} une \idx\vrule dont la longueur est celle du texte \xE0 souligner, soit \verb|\wd0|, de profondeur \verb|\dp0+1.4pt| et de hauteur n\xE9gative \xE9gale \xE0 \verb|-\dp0-1pt|. Nous allons ensuite rendre nulles toutes les dimensions de la boite afin que son encombrement soit nul dans toutes les directions. Enfin, apr\xE8s \xEAtre \xE9ventuellement sorti du mode vertical\idx*{mode!vertical}, nous affichons cette boite \no0\idx*{boite!\no0} avant le texte  :
+
+\showcode/\def\souligne#1{%\xA4\xA7*\souligne\xA4
+	\setbox0=\hbox{#1}% stocke le contenu dans le registre no 0\xA4\idx*\setbox\xA4
+	\setbox0=\hbox{% puis, dans une \hbox, construit une r\xE9glure\xA4\idx*\setbox\xA4
+		\vrule width\wd0 % de la longueur du contenu\xA4\idx*\vrule\idx*\wd\xA4
+			depth\dimexpr\dp0 + 1.4pt\relax % dp = profondeur texte + 1.4pt\xA4\idx*\dimexpr\xA4
+			height\dimexpr-\dp0 - 1pt\relax % ht = -profondeux texte - 1pt
+	}%
+	\wd0=0pt \dp0=0pt \ht0=0pt % annule toutes les dimensions\xA4\idx*\wd\idx*\ht\idx*\dp\xA4
+	\leavevmode \box0 % affiche la r\xE9glure\xA4\idx*\leavevmode\idx*\box\xA4
+	#1% puis le contenu
+}
+Voici \souligne{du texte normal}.\par
+Voici \souligne{du texte profond}.\xA4\xA7*\souligne\xA4/
+
+Compte tenu des dimensions utilis\xE9es, le bord sup\xE9rieur de la r\xE9glure est tr\xE8s exactement \xE0 \verb|1pt| sous la plus basse partie du texte \xE0 souligner.
+
+La variante \xA7\Souligne est plus simple : il ne faut pas tenir compte de la profondeur du registre \no0\idx*{boite!\no0}.
+
+\showcode/\def\Souligne#1{%\xA4\xA7*\Souligne\xA4
+	\setbox0=\hbox{#1}%\xA4\idx*\setbox\xA4
+	\setbox0=\hbox{\vrule width\wd0 depth1.4pt height-1pt }%\xA4\idx*\vrule\idx*\wd\xA4
+	\wd0=0pt \dp0=0pt \ht0=0pt \xA4\idx*\wd\idx*\ht\idx*\dp\xA4
+	\leavevmode \box0 #1%\xA4\idx*\leavevmode\idx*\box\xA4
+}
+Voici \Souligne{du texte normal}.\par
+Voici \Souligne{du texte profond}.\xA4\xA7*\Souligne\xA4/
+
+Les macros pr\xE9sent\xE9es ici ne permettent pas de souligner un texte trop long ou trop proche d'une \idx{fin de ligne}, car une r\xE9glure, \emph{a fortiori} enferm\xE9e dans une \idx\hbox, ne peut franchir une coupure de ligne.
+
+Une autre m\xE9thode, impliquant \idx\lower, aurait \xE9galement \xE9t\xE9 envisageable :
+
+\showcode/\def\Souligne#1{%
+	\setbox0=\hbox{#1}%\xA4\idx*\setbox\xA4
+	\lower 1pt % abaisser \xE0 1pt sous la ligne de base\xA4\idx*\lower\xA4
+		\rlap{% une \hbox en surimpression vers la droite\xA4\idx*\rlap\xA4
+			\vrule width\wd0 height0pt depth0.4pt % contenant le soulignement
+		}%
+	#1% puis afficher le <texte>
+}
+Voici \Souligne{du texte normal}.\par
+Voici \Souligne{du texte profond}.\xA4\xA7*\Souligne\xA4/
+
+La m\xE9thode n'est pas \xE9quivalente car dans ce dernier cas, la r\xE9glure qui tient lieu de soulignement est prise en compte dans la boite englobante de \xA7\Souligne\verb|<texte>|, ce qui n'\xE9tait pas le cas dans le premier code.
+\end{exercice}\idx*[|)]{souligner}
+
+\subsection{Empiler des boites}\idx*[|(]{boite!empilement}
+Essayons maintenant de jouer avec les boites et pour cela, cr\xE9ons une macro \xA7\stackbox capable d'empiler des boites encadr\xE9es, toutes identiques, aussi bien horizontalement que verticalement. Le fait qu'elles soient identiques implique \xE9videmment que les dimensions de leurs contenus ne sont pas trop diff\xE9rentes. La syntaxe de la macro \xA7\stackbox pourrait \xEAtre :
+
+\centrecode-\stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}-
+
+\noindent Et le r\xE9sultat serait :
+
+\begin{centrage}
+\small\vbox{\frboxsep=3pt \stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}}
+\end{centrage}
+
+En ce qui concerne les dimensions des boites, on pourrait parcourir lors d'une premi\xE8re passe tous les arguments afin de trouver la plus grande des hauteurs, largueurs et profondeurs et ensuite prendre ces maximums comme dimension de chaque boite, qui seraient alors compos\xE9es lors d'une seconde passe. Afin de ne pas inutilement compliquer le code\footnote{La vraie et inavouable raison est que renoncer \xE0 faire deux passes va nous donner l'occasion de d\xE9couvrir les \xAB \idx{strut}s \xBB !}, nous allons plut\xF4t d\xE9cider que l'utilisateur va lui-m\xEAme fixer la largueur \emph{interne} des cadres \xE0 l'aide d'un registre de dimension \verb|\stackwd| cr\xE9\xE9 pour l'occasion : ceci suppose \xE9videmment qu'aucune boite ne doit avoir un contenu dont la largeur exc\xE8de \verb|\stackwd|.
+
+Parcourir l'ensemble des contenus va \xEAtre facilit\xE9e avec la macro \xA7\doforeach \xE0 qui nous donnerons la liste d'\xE9l\xE9ments d'une m\xEAme ligne. Tout cela se fait ais\xE9ment avec une macro \verb|\stackbox at i| \xE0 arguments d\xE9limit\xE9s par \xAB\verb|\\|\xBB dont le but est d'isoler et lire  la ligne en cours. Son texte de param\xE8tre sera :
+
+\centrecode-\def\stackbox at i#1\\{...}-
+
+En premier lieu, la macro chapeau se contentera d'appeler la macro r\xE9cursive \verb|\stackbox at i| de cette fa\xE7on :
+
+\centrecode-\stackbox at i#1\\\quark\\-\xA7*\quark
+
+\noindent Ceci a deux avantages : c'est l'assurance que \verb|\\| est pr\xE9sent dans l'argument, car apr\xE8s tout, on pourrait ne pas l'\xE9crire dans l'argument de \xA7\stackbox si on ne voulait qu'une seule ligne. L'autre avantage est que la derni\xE8re ligne \xE0 lire est le \idx{quark} \xAB\xA7\quark\xBB. Si la \tidx[|etc]{ifx}-\xE9galit\xE9 de l'argument \verb|#1| avec \xA7\quark est vraie, nous serons alors surs que la ligne pr\xE9c\xE9dente \xE9tait la derni\xE8re et donc, finir le processus. Nous aurons donc lu la totalit\xE9 des lignes une premi\xE8re fois dans la macro chapeau puis chaque ligne une seule fois dans la macro r\xE9cursive. Chaque ligne a \xE9t\xE9 donc lue deux fois exactement. C'est la m\xE9thode pr\xE9conis\xE9e par la r\xE8gle de la page~\pageref{lire.arguments} pour lire une s\xE9rie d'arguments.
+
+La macro \idx\nobreak, ins\xE9r\xE9e avant chaque ligne restante, interdit toute coupure de page entre deux lignes de boites cons\xE9cutives. Cette macro est d\xE9finie dans plain-\TeX{} et son texte de remplacement est \xAB \idx\penalty\verb|10000| \xBB. Sachant que toute p\xE9nalit\xE9 sup\xE9rieure \xE0 \numprint{10000} est comprise comme \numprint{10000}, il s'agit l\xE0 de la plus forte \idx{p\xE9nalit\xE9} possible ce qui explique qu'une coupure de page ne se fera jamais \xE0 cet endroit.
+
+\showcode/\newdimen\stackwd \stackwd=3em % dimension horizontale interne des cadres\xA4\idx*\newdimen\xA4
+\catcode`@11
+\def\stackbox#1{%\xA4\xA7*\stackbox\xA4
+	\par% termine le paragraphe en cours
+	\noindent\xA4\idx\noindent\xA4
+	\stackbox at i#1\\\quark\\% ajoute "\\\quark\\" \xE0 la fin et appelle \stackbox at i\xA4\xA7*\quark\xA4
+	\par
+}
+
+\def\stackbox at i#1\\{% #1=ligne courante
+	\def\temp@{#1}% stocke la ligne courante
+	\unless\ifx\quark\temp@% si ce n'est pas la fin\xA4\tidx*{unless}\xA7*\quark\xA4
+		\hfill % ressort infini de centrage (et fait passer en mode horizontal)\xA4\idx*\hfill\idx*{mode!horizontal}\xA4
+		\noindent\xA4\idx*\noindent\xA4
+		\doforeach\current at item\in{#1}% pour chaque \xE9l\xE9ment dans la ligne courante...\xA4\xA7*\doforeach\xA4
+			{\frbox{% ...encadrer\xA4\xA7*\frbox\xA4
+				\hbox to\stackwd{% une \hbox de largeur \stackwd\xA4\idx*\hbox\xA4
+					\hss% ressort de centrage\xA4\idx*\hss\xA4
+					\current at item% l'\xE9l\xE9ment courant
+					\hss% ressort de centrage
+					}
+				}% fin de la \frbox
+			}% fin \doforeach
+		\hfill% ressort infini de centrage\xA4\idx*\hfill\xA4
+		\null% assure que le dernier ressort est pris en compte\xA4\idx*\null\xA4
+		\par% finir le paragraphe
+		\nobreak% interdire une coupure de page\xA4\idx*\nobreak\xA4
+		\nointerlineskip% ne pas ins\xE9rer le ressort d'interligne\xA4\idx*\nointerlineskip\xA4
+		\expandafter\stackbox at i% et recommencer
+	\fi
+}
+\catcode`@12
+
+\frboxrule=0.5pt \frboxsep=3pt \xA4\xA7*\frboxsep \xA7*\frboxrule\xA4
+\stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}\xA4\xA7*\stackbox\xA4/
+
+Le r\xE9sultat est loin d'\xEAtre celui escompt\xE9 ! \Qu oique pas si loin que \xE7a, apr\xE8s tout : les positions horizontales sont bonnes. Le bug vient du fait que nous n'avions pas pr\xE9vu que les dimensions verticales (hauteur et profondeur) des \xE9l\xE9ments influaient naturellement sur la boite encadr\xE9e construite. On peut y rem\xE9dier en ins\xE9rant un \xAB \idx{strut}\footnote{On dit \xAB poutre \xBB en fran\xE7ais mais ce mot est assez peu usit\xE9.} \xBB : c'est une r\xE9glure invisible, mais qui s'\xE9tend sur une dimension horizontale ou verticale. La question que l'on se pose imm\xE9diatement est \xAB comment rendre une r\xE9glure invisible ?\xBB Tout simplement en mettant sa largeur \xE0 \verb|0pt|, auquel cas elle aura une dimension verticale ou bien en mettant sa hauteur et profondeur \xE0 \verb|0pt| et dans ce cas, elle aura alors une dimension horizontale. Comme il est assez difficile de montrer des choses invisibles, voici une r\xE9glure de type \idx\vrule rendue visible (son \xE9paisseur est \verb|0.2pt|) apr\xE8s la lettre \xAB a \xBB :
+
+\showcode/a\vrule width0.2pt height15pt depth0pt \quad\xA4\idx*\vrule\xA4
+a\vrule width0.2pt height0pt depth5pt \quad
+a\vrule width0.2pt height10pt depth10pt \quad
+a\vrule width1cm height0.2pt depth0pt\xA4\idx*\vrule\xA4/
+
+Il suffit d'imposer \verb|0pt| comme dimension d'\xE9paisseur pour rendre cette r\xE9glure invisible, mais bien r\xE9elle en ce qui concerne son encombrement. Voici comment la mettre en \xE9vidence en encadrant au plus proche l'ensemble form\xE9 par la lettre \xABa\xBB et le \idx{strut} :
+
+\showcode/\frboxsep0pt %encadrement au plus proche\xA4\xA7*\frboxsep\xA4
+\leavevmode\xA4\idx*\leavevmode\xA4
+\frbox{a\vrule width0pt height15pt depth0pt }\quad\xA4\xA7*\frbox\idx*\vrule\xA4
+\frbox{a\vrule width0pt height0pt depth5pt }\quad
+\frbox{a\vrule width0pt height10pt depth10pt }\quad
+\frbox{a\vrule width1cm height0pt depth0pt }\xA4\idx*\vrule\xA7*\frbox\xA4/
+
+\begin{exercice}
+Construire une macro \xA7\rectangle\verb|{<x>}{<y>}| o\xF9 \verb|<x>| et \verb|<y>| sont des dimensions et qui construit un rectangle dont les dimensions internes (c'est-\xE0-dire de bord interne \xE0 bord interne) sont \verb|<x>| et \verb|<y>|.
+\solution
+Il faut construire une \xA7\frbox dans laquelle nous allons mettre \emph{deux} \idx{strut}s, l'un pour la dimension verticale et l'autre pour l'horizontale.
+
+\showcode/\def\rectangle#1#2{%\xA4\xA7*\rectangle\xA4
+	\begingroup% dans un groupe
+		\frboxsep = 0pt % encadrer au plus proche\xA4\xA7*\frboxsep\xA4
+		\frboxrule= 0.4pt % en traits assez fins
+		\frbox{%\xA4\xA7*\frbox\xA4
+			\vrule width#1 height0pt depth0pt %strut horizontal\xA4\idx*\vrule\xA4
+			\vrule width0pt height#2 depth0pt %strut vertical\xA4\idx*\vrule\xA4
+		}%
+	\endgroup% fermer le groupe
+}
+Carr\xE9 de 0.5 cm : \rectangle{0.5cm}{0.5cm}\smallskip\xA4\idx*\smallskip\xA4
+
+Rectangle de 2.5cm par 3pt : \rectangle{2.5cm}{3pt}\xA4\xA7*\rectangle\xA4/
+\end{exercice}
+
+Pour nos boites cr\xE9\xE9es avec \xA7\stackbox, nous allons mettre dans chacune d'elles un \idx{strut} dont les dimensions verticales sont les plus grandes que l'on peut rencontrer dans un texte \xAB normal \xBB. Nous prendrons les dimensions verticales d'une \idx\hbox contenant \xAB\xC0gjp\xBB. Bien \xE9videmment, si un \xE9l\xE9ment contient un texte dont les dimensions verticales exc\xE8dent celles du \idx{strut}, le probl\xE8me r\xE9apparaitra.
+
+Il y a un autre d\xE9faut, plus difficile \xE0 d\xE9tecter dans notre macro \xA7\stackbox : les r\xE9glures des boites adjacentes ne se superposent pas, aussi bien horizontalement que verticalement, ce qui fait que leurs \xE9paisseurs s'additionnent. Lorsque \xA7\frboxrule est faible (\verb|0.5pt| ici), cela n'a pas d'influence visuelle notable, mais ce d\xE9faut serait beaucoup plus visible si \xA7\frboxrule valait 2pt par exemple. Nous allons donc ins\xE9rer une espace n\xE9gative avec \verb|\kern-\frboxrule| entre chaque boite horizontalement et entre chaque ligne verticalement. Le dernier \idx\kern horizontal, qui viendra apr\xE8s la derni\xE8re boite dans la boucle, sera annul\xE9 par la primitive \idx\unkern que nous mettons apr\xE8s la boucle :
+
+\showcode|\newdimen\stackwd \stackwd=3em \xA4\idx*\newdimen\xA4
+\catcode`\@11
+\def\stackbox#1{%\xA4\xA7*\stackbox\xA4
+	\par% termine le paragraphe en cours
+	\begingroup% dans un groupe semi-simple
+		\parindent=0pt% pas d'indentation\xA4\idx*\parindent\xA4
+		\parskip=0pt% annuler le \parskip\xA4\idx*\parskip\xA4
+		\setbox0\hbox{\xC0gjp}% boite pour le strut\xA4\idx*\setbox\idx*\hbox\xA4
+		\edef\stack at strut{\vrule width\z@ height\the\ht0 depth\the\dp0 }% d\xE9finit le strut\xA4\idx*\vrule\idx*\z@\xA4
+		\stackbox at i#1\\\quark\\% ajoute "\\\quark\\" \xE0 la fin et appelle \stackbox at i\xA4\xA7*\quark\xA4
+		\unkern% annule la derni\xE8re compensation verticale
+		\par
+	\endgroup
+}
+\def\stackbox at i#1\\{% #1=ligne courante
+	\def\temp@{#1}% stocke la ligne courante
+	\unless\ifx\quark\temp@% si ce n'est pas la fin\xA4\tidx*{unless}\xA7*\quark\xA4
+		\hfill % ressort infini de centrage (passe en mode horizontal)\xA4\idx*\hfill\idx*{mode!horizontal}\xA4
+		\doforeach\current at item\in{#1}% pour chaque \xE9l\xE9ment dans la ligne courante...\xA4\xA7*\doforeach\xA4
+			{\frbox{% ...encadrer\xA4\xA7*\frbox\xA4
+				\hbox to\stackwd{% une \hbox de largeur \stackwd contenant\xA4\idx*\hbox\xA4
+					\hss%         1) ressort de centrage\xA4\idx*\hss\xA4
+					\stack at strut% 2) strut de dimension verticale
+					\current at item%3) l'\xE9lement courant
+					\hss}%        4)ressort de centrage
+				}% fin de la \fbox
+			\kern-\frboxrule% revenir en arri\xE8re pour superposer les r\xE9glures verticales\xA4\idx*\kern\xA4
+			}% fin de \doforeach
+		\unkern% annuler la derni\xE8re compensation horizontale\xA4\idx*\unkern\xA4
+		\hfill% ressort infini de centrage\xA4\idx*\hfill\xA4
+		\null% fait prendre en compte le dernier ressort\xA4\idx*\null\xA4
+		\par% termine le paragraphe
+		\nobreak% interdit une coupure de page\xA4\idx*\nobreak\xA4
+		\nointerlineskip% sinon, ne pas ajouter le ressort d'interligne\xA4\idx*\nointerlineskip\xA4
+		\kern-\frboxrule% superposer les r\xE9glures horizontales\xA4\idx*\kern\xA7*\frboxrule\xA4
+		\expandafter\stackbox at i% et recommencer
+	\fi
+}
+\frboxrule=0.5pt \xA4\xA7*\frboxrule\xA4
+\frboxsep=3pt \xA4\xA7*\frboxsep\xA4
+\stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}|
+
+\begin{exercice}
+Modifier la macro \xA7\stackbox en \xA7\lineboxed[|(] de telle sorte que pour chaque ligne, les boites aient une largeur telle qu'elles occupent la totalit\xE9 de la ligne.
+\solution
+Pour que la largeur des boites d'une ligne soit telle que toutes ces boites remplissent la ligne, nous devons d'abord savoir combien il y a de boites dans chaque ligne. Pour cela, il faut compter combien de virgules il y a dans l'argument \verb|#1| et ajouter 1 ou, m\xE9thode plus simple, rajouter une virgule \xE0 \verb|#1| et effectuer le comptage. La macro \xA7\cnttimestocs se chargera de ce travail et assignera le nombre de boites $n$ dans une macro.
+
+La largeur disponible pour tous les contenus cumul\xE9s de toutes les boites de la ligne s'obtient en retirant de \idx\hsize l'\xE9paisseur \xA7\frboxrule des r\xE9glures verticales et les espaces \xA7\frboxsep entre ces r\xE9glures et les contenus des boites. S'il y a $n$ boites, il y a $n+1$ r\xE9glures verticales et $2n$ espaces \xA7\frboxsep. La largeur interne d'une boite, stock\xE9e dans la macro \verb|\dim at box| sera donc
+
+\[
+\frac{\hbox{\ttfamily\char`\\hsize}-(n+1)\hbox{\ttfamily\char`\\frboxrule}-2n\hbox{\ttfamily\char`\\frboxsep}}{n}
+\]
+
+\showcode|\catcode`\@11
+\def\lineboxed#1{%\xA4\xA7*\lineboxed\xA4
+	\par% termine le paragraphe en cours
+	\begingroup% dans un groupe semi-simple
+		\parindent=0pt% pas d'indentation\xA4\idx*\parindent\xA4
+		\parskip=0pt% annuler le \parskip\xA4\idx*\parskip\xA4
+		\setbox0\hbox{\xC0gjp}% boite pour le strut\xA4\idx*\setbox\idx*\hbox\xA4
+		\edef\stack at strut{\vrule width\z@ height\the\ht0 depth\the\dp0 }% d\xE9finit le strut\xA4\idx*\vrule\idx*\z@\xA4
+		\lineboxed at i#1\\\quark\\% ajoute "\\\quark\\" \xE0 la fin et appelle la macro r\xE9cursive\xA4\xA7*\quark\xA4
+		\unkern% annule la derni\xE8re compensation verticale
+		\par
+	\endgroup
+}
+\def\lineboxed at i#1\\{% #1=ligne courante
+	\def\temp@{#1}% stocke la ligne courante
+	\unless\ifx\quark\temp@% si ce n'est pas la fin\xA4\tidx*{unless}\xA7*\quark\xA4
+		\cnttimestocs{#1,}{,}\nb at args% re\xE7oit le nombre d'arguments dans la ligne courante\xA4\xA7*\cnttimestocs\xA4
+		\edef\dim at box{\the\dimexpr(\hsize-\frboxrule*(\nb at args+1)-
+		              \frboxsep*2*\nb at args)/\nb at args}%\xA4\idx*\the\idx*\dimexpr\xA7*\frboxrule\xA7*\frboxsep\xA4
+		\hbox{%\xA4\idx*\hbox\xA4
+			\doforeach\current at item\in{#1}% pour chaque \xE9l\xE9ment dans la ligne courante...\xA4\xA7*\doforeach\xA4
+				{\frbox{% ...encadrer\xA4\xA7*\frbox\xA4
+					\hbox to\dim at box{% une \hbox de largeur \dim at box contenant
+						\hss%         1) ressort de centrage\xA4\idx*\hss\xA4
+						\stack at strut% 2) strut de dimension verticale
+						\current at item%3) l'\xE9lement courant
+						\hss}%        4)ressort de centrage
+					}% fin de la \fbox
+				\kern-\frboxrule% revenir en arri\xE8re pour superposer les r\xE9glures verticales\xA4\idx*\kern\xA7*\frboxrule\xA4
+				}% fin de \doforeach
+			\unkern% annuler la derni\xE8re compensation horizontale\xA4\idx*\unkern\xA4
+		}%
+		\par% termine le paragraphe
+		\nobreak% interdit une coupure de page\xA4\idx*\nobreak\xA4
+		\nointerlineskip% sinon, ne pas ajouter le ressort d'interligne\xA4\idx*\nointerlineskip\xA4
+		\kern-\frboxrule% superposer les r\xE9glures horizontales\xA4\idx*\kern\xA7*\frboxrule\xA4
+		\expandafter\lineboxed at i% et recommencer
+	\fi
+}
+\catcode`\@12
+\lineboxed{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}\medbreak\xA4\idx*\medbreak\xA4
+
+\frboxrule=1.5pt \xA4\xA7*\frboxrule\xA4
+\frboxsep=3pt \xA4\xA7*\frboxrule\xA4
+\lineboxed{,,,,,,,\\,,\\,,,,,,}|\xA7*\lineboxed[|)]\end{exercice}\idx*[|)]{boite!empilement}
+
+\subsection{Dessiner des quadrillages}\idx*[|(]{quadrillages}
+Comment parler de r\xE9glure sans parler de quadrillage ? Car s'il est bien un domaine o\xF9 elles sont adapt\xE9es, c'est bien celui-l\xE0.
+
+Mettons \xE0 profit ce que nous savons pour \xE9crire une macro \xA7\grid[|(], capable de dessiner des quadrillages tels que celui-ci :
+
+\begin{centrage}
+\xunit=1.5cm \yunit=1cm \mainrule=1pt \subrule=0.2pt
+\leavevmode\grid{5}{4}{2}{10}
+\end{centrage}
+
+Avant d'entrer dans le vif du sujet, quel est le nombre de param\xE8tres qu'il est n\xE9cessaire de sp\xE9cifier ? L'observation de ce quadrillage permet de se faire une id\xE9e. Il faut d\xE9finir la largeur et hauteur d'un carreau-unit\xE9 que nous stockerons dans deux registres de dimension (\verb|\xunit| et \verb|\yunit|) ainsi que l'\xE9paisseur des lignes principales et secondaires stock\xE9es dans deux autres registres de dimension (\verb|\mainrule| et \verb|\subrule|). Puis, il faut passer \xE0 la macro \xA7\grid le nombre de carreaux-unit\xE9 que l'on veut horizontalement et verticalement ainsi que le nombre de subdivisions horizontales et verticales dans chaque carreau. Il semble donc naturel de construire une macro utilisant 4 registres de dimension et admettant 4 arguments.
+
+Le quadrillage ci-dessus a \xE9t\xE9 trac\xE9 en ex\xE9cutant
+
+\centrecode-\grid{5}{4}{2}{10}-
+
+\noindent pour demander qu'il comporte 5 carreaux-unit\xE9 horizontalement, chacun divis\xE9 en 4 et 2 carreaux-unit\xE9 verticalement, chacun divis\xE9 en 10. De plus, les registres de dimension ont \xE9t\xE9 initialis\xE9s avec
+
+\centrecode-\xunit=1.5cm \yunit=1cm \mainrule=1pt \subrule=0.2pt-
+
+\subsubsection{R\xE9glures horizontales}
+Construisons la macro \xA7\grid pas \xE0 pas et d\xE9cidons que cette macro mettra des \xE9l\xE9ments dans une \idx\vbox.Nous allons dans un premier temps empiler des \xE9l\xE9ments dans une liste verticale pour tracer les r\xE9glures horizontales. Il est bien entendu que l'\xE9paisseur des r\xE9glures ne doit pas perturber les espacements verticaux, c'est pourquoi elles doivent \xEAtre mises dans une sous-boite de hauteur nulle. Nous allons donc d\xE9finir l'analogue de \xA7\clap mais pour les \idx\vbox. La macro suivante, \xA7\vlap enferme son argument dans une boite verticale et rend la hauteur du tout \xE9gale \xE0 \verb|0pt| :
+
+\centrecode-\def\vlap#1{\vbox to0pt{\vss#1\vss}}-\idx*\vss
+
+Chaque r\xE9glure horizontale doit avoir comme largeur \verb|\xunit*#1|, que nous stockerons dans une macro pour l'utiliser ensuite. Pour que les espacements verticaux soient rigoureusement exacts, le ressort inter-ligne doit \xEAtre neutralis\xE9 et pour cela, \idx\offinterlineskip sera appel\xE9 au d\xE9but de la \idx\vbox. Voici un premier essai o\xF9 ne sont construites que les r\xE9glures horizontales principales. On prend les unit\xE9s \xE9gales \xE0 \numprint[cm]{0.5} par souci de gain de place.
+
+\showcode/\xunit=0.5cm \yunit=0.5cm \mainrule=0.8pt \subrule=0.2pt
+\def\vlap#1{\vbox to0pt{\vss#1\vss}}\xA4\xA7*\vlap\idx*\vss\xA4
+\catcode`@11
+\def\grid#1#2#3#4{%\xA4\xA7*\grid\xA4
+	\vbox{% empiler les \xE9l\xE9ments verticalement\xA4\idx*\vbox\xA4
+		\offinterlineskip% pas de ressort d'interligne\xA4\idx*\offinterlineskip\xA4
+		\edef\total at wd{\the\dimexpr\xunit*#1\relax}% largeur totale ds r\xE9glures\xA4\idx*\the\idx*\dimexpr\xA4
+		\for\ii = 1 to #3 \do1% pour chaque carreau vertical (\ii=variable muette)\xA4\xA7*\for\xA4
+			{\vlap{\hrule width\total at wd height\mainrule}% tracer la r\xE9glure horizontale\xA4\idx*\hrule\xA7*\vlap\xA4
+			\kern\yunit% ins\xE9rer l'espace vertical\xA4\idx*\kern\xA4
+			}%
+		\vlap{\hrule width\total at wd height\mainrule}% derni\xE8re r\xE9glure horizontale\xA4\xA7*\vlap\xA4
+	}%
+}
+\catcode`@12
+\setbox0\hbox{\grid{4}{}{3}{}}% range la quadrillage dans le registre no 0\xA4\idx*\setbox\idx*\hbox\xA4
+Essai \copy0{} qui a pour
+largeur=\convertunit{\wd0}{cm} cm et pour hauteur=\convertunit{\ht0}{cm} cm\xA4\xA7*\convertunit\idx*\ht\idx*\wd\xA4/
+
+Pour s'assurer que les dimensions du quadrillage sont parfaitement correctes, le quadrillage a \xE9t\xE9 plac\xE9 dans une \idx\hbox stock\xE9e dans le registre de boite \no0\idx*{boite!\no0}. Ainsi, nous pouvons mesurer sa largeur et sa hauteur (converties en \verb|cm| avec la macro \xA7\convertunit vue pr\xE9c\xE9demment) : les dimensions obtenues sont bien \numprint[cm]2 de largeur et \numprint[cm]{1.5} en hauteur qui correspondent \xE0 4\verb|\xunit| et \xE0 3\verb|\yunit|.
+\grandsaut
+
+Venons-en aux lignes horizontales de subdivisions. Elles seront plac\xE9es imm\xE9diatement \emph{sous} la position courante de la r\xE9glure principale en cours, moyennant un ressort \idx\vss ins\xE9r\xE9 en fin de \idx\vbox. Le code suivant illustre cette structure :
+
+\showcode/D\xE9but\vbox to0pt{\hbox{sous}\hbox{la ligne de base}\vss}suite\xA4\idx*\vss\xA4/
+\grandsaut
+
+Dans le cas pr\xE9sent, nous placerons sous la position de la r\xE9glure principale en cours le mat\xE9riel suivant, r\xE9p\xE9t\xE9 \verb|#4|${}-{}1$ fois   :
+
+\begin{itemize}
+	\item l'espace verticale de dimension \verb|\yunit/#4|;
+	\item la r\xE9glure secondaire, enferm\xE9e dans une \xA7\vlap, de fa\xE7on \xE0 ce que son \xE9paisseur n'entre pas en ligne de compte.
+\end{itemize}
+
+\noindent Remarquons qu'il n'y a pas lieu de tester si \verb|#4|${}>1$, car la boucle \xA7\for suivante 
+
+\centrecode-\for\jj = 2 to #4 \do 1 {<code \xE0 ex\xE9cuter>}-
+
+\noindent ne s'ex\xE9cutera que si le test est vrai.
+
+\showcode|\xunit=0.5cm \yunit=0.5cm \mainrule=0.8pt \subrule=0.2pt
+\def\vlap#1{\vbox to0pt{\vss#1\vss}}\xA4\xA7*\vlap\idx*\vss\xA4
+\catcode`@11
+\def\grid#1#2#3#4{%\xA4\xA7*\grid\xA4
+	\vbox{% empiler les \xE9l\xE9ments verticalement\xA4\idx*\vbox\xA4
+		\offinterlineskip% pas de ressort d'interligne\xA4\idx*\offinterlineskip\xA4
+		\edef\total at wd{\the\dimexpr\xunit*#1\relax}% largeur totale de la boite\xA4\idx*\the\idx*\dimexpr\xA4
+		\edef\sub at unit{\the\dimexpr\yunit/#4\relax}% hauteur verticale de la subdivision
+		\for\ii = 1 to #3 \do% pour chaque unit\xE9 verticale en partant du haut, tracer :\xA4\xA7*\for\xA4
+			{\vlap{\hrule width\total at wd height\mainrule}% la r\xE9glure horizontale principale\xA4\xA7*\vlap\xA4
+			% et dessous, les r\xE9glures horizontales secondaires :
+			\vbox to\z@{% dans une \vbox de hauteur nulle,\xA4\idx*\vbox\idx*\z@\xA4
+				\for\jj = 2 to #4 \do 1% ins\xE9rer #4-1 fois sous la position courante :\xA4\xA7*\for\xA4
+					{\kern\sub at unit % l'espace verticale\xA4\idx*\kern\xA4
+					\vlap{\hrule width\total at wd height\subrule}% et la r\xE9glure secondaire\xA4\xA7*\vlap\idx*\vrule\xA4
+					}%
+				\vss% ressort qui se comprime pour satisfaire la hauteur nulle\xA4\idx*\vss\xA4
+			}%
+			\kern\yunit% ins\xE9rer l'espace vertical entre r\xE9glures principales\xA4\idx*\kern\xA4
+			}%
+		\vlap{\hrule width\total at wd height\mainrule}% derni\xE8re r\xE9glure principale du bas\xA4\xA7*\vlap\xA4
+	}%
+}
+\catcode`@12
+\setbox0=\hbox{\grid{4}{}{3}{5}}\xA4\idx*\setbox\xA4
+Essai \copy0{} qui a pour
+largeur=\convertunit{\wd0}{cm} cm et pour hauteur=\convertunit{\ht0}{cm} cm\xA4\idx*\wd\idx*\ht\xA7*\convertunit\xA4|
+
+\subsubsection{R\xE9glures verticales}
+Pour les r\xE9glures verticales, nous allons proc\xE9der exactement de la m\xEAme fa\xE7on qu'avec les r\xE9glures horizontales. Nous allons les tracer avant les r\xE9glures horizontales et le tout sera enferm\xE9 dans une \idx\vbox chapeau contenant la totalit\xE9 du quadrillage.
+
+Afin que ces r\xE9glures verticales ne prennent aucun encombrement vertical, nous les enfermerons dans une \idx\vbox de hauteur nulle et ferons en sorte que le contenu de cette boite se place au-dessous de la plus haute position de la \idx\vbox chapeau en utilisant \xE0 nouveau cette structure :
+
+\centrecode-\vbox to0pt{<r\xE9glures verticales>\vss}-\idx*\vss
+
+La totalit\xE9 des r\xE9glures verticales sera mise dans une \idx\rlap, c'est-\xE0-dire en d\xE9bordement \xE0 droite de la position courante :
+
+\centrecode-\vbox to0pt{\rlap{<r\xE9glures verticales>}\vss}-\idx*\vss
+
+Il est maintenant clair que, puisque la \idx\rlap a une largeur nulle, cette \idx\vbox aura toutes ses dimensions nulles. Cela signifie que toutes les r\xE9glures verticales seront dessin\xE9es sans que la position courante ne change.
+
+\showcode|\mainrule=0.8pt \subrule=0.2pt
+\def\vlap#1{\vbox to0pt{\vss#1\vss}}\xA4\xA7*\vlap\idx*\vss\xA4
+\catcode`@11
+\def\grid#1#2#3#4{%\xA4\xA7*\grid\xA4
+	\vbox{% empiler les \xE9l\xE9ments verticalement\xA4\idx*\vbox\xA4
+		\offinterlineskip% pas de ressort d'interligne\xA4\idx*\offinterlineskip\xA4
+		% #################### Trac\xE9 des r\xE9glures verticales ####################
+		\vbox to\z@{% dans une \vbox de hauteur nulle\xA4\idx*\vbox\idx*\z@\xA4
+			\edef\total at ht{\the\dimexpr\yunit*#3\relax}% hauteur totale\xA4\idx*\the\idx*\dimexpr\xA4
+			\edef\sub at unit{\the\dimexpr\xunit/#2\relax}% espace entre 2 subdivisions
+			\rlap{% mettre \xE0 droite de la position sans bouger\xA4\idx*\rlap\xA4
+				\for\ii = 1 to #1 \do 1% pour chaque unit\xE9 horizontale\xA4\xA7*\for\xA4
+					{\clap{\vrule width\dimexpr\mainrule height\total at ht}% r\xE9glure principale\xA4\idx*\vrule\xA7*\clap\xA4
+					\rlap{% mettre \xE0 droite de la position sans bouger\xA4\idx*\rlap\xA4
+						\for\jj = 2 to #2 \do 1% ins\xE9rer #2-1 fois
+							{\kern\sub at unit % l'espace horizontal\xA4\idx*\kern\xA4
+							\clap{\vrule width\subrule height\total at ht}% et la r\xE9glure verticale\xA4\xA7*\clap\idx*\vrule\xA4
+							}%
+					}%
+					\kern\xunit % ins\xE9rer l'espace entre r\xE9glures horizontales
+					}%
+				\clap{\vrule width\mainrule height\total at ht}% derni\xE8re r\xE9glure principale\xA4\idx*\vrule\xA7*\clap\xA4
+			}%
+			\vss% compense la hauteur=0pt de la \vbox\xA4\idx*\vss\xA4
+		}%
+		% #################### Trac\xE9 des r\xE9glures horizontales ####################
+		\edef\total at wd{\the\dimexpr\xunit*#1\relax}% largeur totale de la boite\xA4\idx*\the\idx*\dimexpr\xA4
+		\edef\sub at unit{\the\dimexpr\yunit/#4\relax}% espace entre 2 subdivisions
+		\for\ii = 1 to #3 \do 1% pour chaque carreau vertical en partant du haut :\xA4\xA7*\for\xA4
+			{\vlap{\hrule width\total at wd height\mainrule}% r\xE9glure horizontale principale\xA4\xA7*\vlap\xA4
+			% et dessous, les r\xE9glures secondaires :
+			\vbox to\z@{% dans une \vbox de hauteur nulle,\xA4\idx*\vbox\idx*\z@\xA4
+				\for\jj = 2 to #4 \do 1% ins\xE9rer #4-1 fois sous la position courante :\xA4\xA7*\for\xA4
+					{\kern\sub at unit % l'espace vertical\xA4\idx*\kern\xA4
+					\vlap{\hrule width\total at wd height\subrule}% et la r\xE9glure secondaire\xA4\xA7*\vlap\idx*\vrule\xA4
+					}%
+				\vss% ressort qui se comprime pour satisfaire la hauteur nulle\xA4\idx*\vss\xA4
+			}%
+			\kern\yunit% ins\xE9rer l'espace vertical entre r\xE9glures principales\xA4\idx*\kern\xA4
+			}%
+		\vlap{\hrule width\total at wd height\mainrule}% derni\xE8re r\xE9glure horizontale\xA4\xA7*\vlap\xA4
+	}%
+}
+\catcode`@12
+Grille 1 : \xunit=1cm \yunit=1cm \grid{5}{10}{2}{10}\smallskip\xA4\idx*\smallskip\xA4
+
+Grille 2 : \xunit=0.5cm \yunit=0.5cm \grid{7}{1}{3}{1}\smallskip\xA4\idx*\smallskip\xA4
+
+Grille 3 : \xunit=1.5cm \yunit=0.5cm \grid{4}{3}{3}{2}|\xA7*\grid[|)]\idx*[|)]{r\xE9glure}\idx*[|)]{quadrillages}
+
+\section{R\xE9p\xE9tition de motifs}\label{repetition.motifs}
+\subsection{\texttt{\char`\\leaders} et ses complices}\idx*[|(]{\leaders}
+Venons-en maintenant \xE0 une primitive int\xE9ressante qui a la capacit\xE9 de r\xE9p\xE9ter une boite autant de fois que n\xE9cessaire pour remplir un espace donn\xE9, que ce soit en mode horizontal\idx*{mode!horizontal} ou vertical\idx*{mode!vertical}. Cette primitive est \idx\leaders et la syntaxe pour le mode horizontal\idx*{mode!horizontal} est la suivante :
+
+\centrecode-\leaders<boite ou r\xE9glure>\hskip<ressort>-
+
+\noindent La syntaxe est la m\xEAme pour le mode vertical\idx*{mode!vertical} sauf que \idx\vskip est utilis\xE9 au lieu de \idx\hskip. En r\xE9alit\xE9, \idx\leaders est juste une assignation pour le \verb|<ressort>| qui sp\xE9cifie tout simplement avec quel motif il doit \xEAtre rempli. Car contrairement aux \idx\kern, un ressort a vocation \xE0 \xEAtre rempli avec quelque chose ! Si \idx\leaders est absent comme cela a \xE9t\xE9 le cas jusqu'\xE0 pr\xE9sent, ce motif est vide ce qui conduit \xE0 des ressorts qui laissent des espaces blancs.
+
+Int\xE9ressons-nous au mode horizontal\idx*{mode!horizontal}, celui en grande majorit\xE9 pour lequel est utilis\xE9e \idx\leaders. Supposons que la boite de \numprint[cm]{1.5} de long suivante
+
+\centrecode-\hbox to1.5cm{\hss A\hss}-
+
+\noindent doive remplir un espace de \numprint[cm]{10}. La primitive \idx\leaders va coller ces boites les unes aux autres de fa\xE7on \xE0 remplir le plus grand espace possible. Ce collage se fera bord \xE0 bord en partant de la gauche et laissera, si la longueur \xE0 remplir n'est pas un multiple de la longueur du motif, une espace laiss\xE9e vide \xE0 la fin. Dans le code ci-dessous, nous sp\xE9cifions \xAB\verb|\hbox to10cm|\xBB pour imposer que la dimension horizontale \xE0 remplir soit de \numprint[cm]{10}. Les \idx\vrule plac\xE9es de part et d'autre de cette \idx\hbox permettent de visualiser le d\xE9but et la fin de cette boite :
+
+\showcode/\vrule\hbox to10cm{\leaders\hbox to1.5cm{\hss A\hss}\hfill}\vrule\xA4\idx*\vrule\idx*\leaders\idx*\hbox\idx*\hfill\xA4/
+
+Comme on peut facilement s'en assurer par calcul mental, seules 6 copies de la boites ont \xE9t\xE9 coll\xE9es les unes aux autres pour remplir un espace de \numprint[cm]9, laissant une espace vide de \numprint[cm]1 \xE0 la fin.
+
+Deux variantes de cette primitive existent et permettent de r\xE9partir l'\xE9ventuelle espace non remplie :
+\begin{itemize}
+	\item avec \idx\cleaders, elle est \xE9galement r\xE9partie avant la premi\xE8re et apr\xE8s la derni\xE8re boite r\xE9p\xE9t\xE9e ;
+	\item avec \idx\xleaders, elle est \xE9galement r\xE9partie avant la premi\xE8re, apr\xE8s la derni\xE8re et entre chaque boite r\xE9p\xE9t\xE9e.
+\end{itemize}
+
+Le plus visuellement compr\xE9hensible est de d\xE9finir cette boite \xAB{\frboxsep=-\frboxrule \frbox{\hbox to1.5cm{\hss A\hss}}}\xBB, de \numprint[cm]{1.5} de long et encadr\xE9e au plus proche par ce code :
+
+\centrecode/\frboxsep=-\frboxrule \frbox{\hbox to1.5cm{\hss A\hss}}/
+
+\noindent et regarder les diff\xE9rences de comportement entre les diff\xE9rentes variantes. Pour bien visualiser l'espace de \numprint[cm]{10} \xE0 remplir, le caract\xE8re actif \xAB\cidx\~\xBB a \xE9t\xE9 programm\xE9 pour imprimer une r\xE9glure horizontale de \verb|1em| de longueur juste avant et juste apr\xE8s cette espace :
+
+\showcode/\frboxsep=-\frboxrule \def~{\leavevmode\raise.75ex\hbox{\vrule height.2pt width1em}}\xA4\xA7*\frboxsep\cidx*\~\idx*\raise\idx*\hbox\idx*\leavevmode\idx*\vrule\xA4
+~\hbox to10cm{\leaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~\xA4\idx*\hfill\idx*\hss\idx*\leaders\xA7*\frbox\xA4
+
+~\hbox to10cm{\cleaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~\xA4\idx*\cleaders\xA4
+
+~\hbox to10cm{\xleaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~\xA4\idx*\xleaders\xA7*\frbox\xA4/
+
+Au lieu d'un encadrement contenant un texte, on peut aussi mettre une r\xE9glure ou m\xEAme plusieurs dans une boite pour faire des dessins rudimentaires :
+
+\showcode+a) \leavevmode\hbox to10cm{\leaders\hrule\hfill}\smallskip\xA4\idx*\leavevmode\idx*\smallskip\xA4
+
+b) \hbox to10cm{\leaders\hbox{\vrule height0.2pt width2.5mm \kern1.5mm}\hfill}\xA4\idx*\leaders\idx*\leavevmode\idx*\hfill\xA4
+
+c) \vrule width0.2pt height1ex depth0pt % premi\xE8re r\xE9glure verticale
+     \hbox to10cm{% puis r\xE9p\xE9tition de "_|"
+     \leaders\hbox{\vrule width2em height0.2pt \vrule width0.2pt height1ex}\hfill}\xA4\idx*\vrule\xA4
+
+d) \hbox to10cm{\leaders\hbox{%\xA4\idx*\leaders\idx*\leavevmode\xA4
+		\vrule height.2pt width.5em% 1/2 palier bas\xA4\idx*\vrule\xA4
+		\vrule height5pt width0.2pt% mont\xE9e au palier haut
+		\vrule height5pt depth-4.8pt width1em% palier haut
+		\vrule height5pt width0.2pt% descente au palier bas
+		\vrule height.2pt width.5em% 1/2 palier bas\xA4\idx*\vrule\xA4
+		}\hfill}+
+
+La macro \idx\hrulefill, qui remplit l'espace disponible avec une r\xE9glure horizontale, est programm\xE9e de la fa\xE7on suivante dans plain-\TeX{} :
+
+\centrecode-\def\hrulefill{\leaders\hrule\hfill}-
+
+\noindent C'est d'ailleurs un cas o\xF9 la primitive \idx\hrule peut \xEAtre appel\xE9e en mode horizontal\idx*{mode!horizontal} pour produire une r\xE9glure horizontale alors que son mode de fonctionnement est le mode vertical\idx*{mode!vertical}.\idx*[|)]{\leaders}
+
+\subsection{Retour sur le quadrillage}
+On entrevoit que la primitive \idx\leaders, de par sa propri\xE9t\xE9 qui est d'effectuer une r\xE9p\xE9tition, peut nous aider \xE0 tracer un quadrillage sans faire explicitement appel \xE0 une boucle ! Pour y arriver, nous allons tout d'abord nous employer \xE0 construire un carreau-unit\xE9 avec les subdivisions ad\xE9quates que \idx\leaders r\xE9p\xE8tera horizontalement et verticalement pour cr\xE9er le quadrillage.
+
+Commen\xE7ons verticalement. S'il faut $n$ subdivisions dans une espace verticale de \verb|\yunit|, il faut empiler verticalement dans une boite de hauteur \verb|\yunit| :
+
+\begin{enumerate}
+	\item une r\xE9glure horizontale d'\xE9paisseur \verb|\mainrule| dont la dimension verticale sera forc\xE9e \xE0 0pt;
+	\item placer autant de fois qu'il est possible ce mat\xE9riel vertical suivant (dont la dimension est \verb|\yunit|/$n$) :
+	\begin{enumerate}
+		\item une espace verticale de dimension \verb|\yunit|/$n$;
+		\item une r\xE9glure horizontale d'\xE9paisseur \verb|\subrule| dont la dimension verticale sera forc\xE9e \xE0 0pt;
+	\end{enumerate}
+	\item une espace verticale de dimension \verb|\yunit|/$n$;
+	\item une r\xE9glure horizontale d'\xE9paisseur \verb|\mainrule| dont la dimension verticale sera forc\xE9e \xE0 0pt.
+\end{enumerate}
+
+Comme les composants du point \no2 prennent \xE0 chaque fois \verb|\yunit|/$n$ d'espace vertical et que les deux derniers composants prennent aussi cette espace, la r\xE9p\xE9tition de l'\xE9l\xE9ment 2 aura donc lieu $n-1$ fois.
+
+\showcode|\mainrule=0.8pt \subrule=0.2pt
+\def\carreau#1#2{% #1=nb subdiv H  #2=nb subdiv V
+	\vbox to\yunit{% dans un \vbox de hauteur \yunit\xA4\idx*\vbox\xA4
+		\offinterlineskip% pas de ressort d'interligne\xA4\idx*\offinterlineskip\xA4
+		\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale du haut\xA4\xA7*\vlap\xA4
+		\leaders% r\xE9p\xE9ter (ici ce sera donc #2-1 fois)\xA4\idx*\leaders\xA4
+			\vbox to\dimexpr\yunit/#2\relax% une \vbox de hauteur \yunit/#2\xA4\idx*\vbox\idx*\dimexpr\xA4
+				{\vss% ressort qui va s'\xE9tirer \xE0 \yunit/#2\xA4\idx*\vss\xA4
+				\vlap{\hrule height\subrule width\xunit}% r\xE9glure de subdiv de dim 0pt
+				}\vfill\xA4\idx*\vfill\xA4
+		\kern\dimexpr\yunit/#2\relax% derni\xE8re espace verticale\xA4\idx*\kern\xA4
+		\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale du bas\xA4\idx*\hrule\xA7*\vlap\xA4
+	}%
+}
+\yunit=1cm
+\leavevmode \carreau{}{4} puis \carreau{}{10}\xA4\idx*\leavevmode\xA4|
+
+Pour les r\xE9glures horizontales, nous allons proc\xE9der de m\xEAme apr\xE8s voir mis tout le code pr\xE9c\xE9dent dans une \idx\rlap de telle sorte que son encombrement horizontal soit nul.
+
+\showcode|\mainrule=0.8pt \subrule=0.2pt
+\def\carreau#1#2{% #1=nb subdiv H  #2=nb subdiv V
+	% ######## r\xE9glures horizontales ########
+	\rlap{% mettre \xE0 droite de la position sans bouger\xA4\idx*\rlap\xA4
+		\vbox to\yunit{% dans un \vbox de hauteur \yunit
+			\offinterlineskip% pas de ressort d'interligne\xA4\idx*\offinterlineskip\xA4
+			\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale du haut\xA4\xA7*\vlap\xA4
+			\leaders% r\xE9p\xE9ter (ici ce sera #2-1 fois)\xA4\idx*\leaders\xA4
+				\vbox to\dimexpr\yunit/#2\relax% une \vbox de hauteur \yunit/#2\xA4\idx*\vbox\idx*\dimexpr\xA4
+					{\vss% ressort qui va s'\xE9tirer \xE0 \yunit/#2\xA4\idx*\vss\xA4
+					\vlap{\hrule height\subrule width\xunit}% r\xE9glure de subdiv de dim 0pt
+					}\vfill% ressort de \leaders\xA4\idx*\vfill\xA4
+			\kern\dimexpr\yunit/#2\relax% derniere espace verticale\xA4\idx*\kern\xA4
+			\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale du bas\xA4\idx*\hrule\xA7*\vlap\xA4
+		}%
+	}%
+	% ######## r\xE9glures verticales ########
+	\hbox to\xunit{% dans une \hbox de longueur \xunit\xA4\idx*\hbox\xA4
+		\clap{\vrule height\yunit width\mainrule}% r\xE9glure principale de gauche\xA4\xA7*\clap\idx*\vrule\xA4
+		\leaders% r\xE9p\xE9ter (ici ce sera #1-1 fois)\xA4\idx*\leaders\xA4
+			\hbox to\dimexpr\xunit/#1\relax\xA4\idx*\dimexpr\idx*\hbox\xA4
+				{\hss% ressort qui va s'\xE9tirer \xE0 \xunit/#1\xA4\idx*\hss\xA4
+				\clap{\vrule height\yunit width\subrule}% r\xE9glure H de dimension 0
+				}\hfill% ressort de \leaders\xA4\idx*\hfill\xA4
+			\kern\dimexpr\xunit/#1\relax% derni\xE8re espace H\xA4\idx*\kern\xA4
+			\clap{\vrule height\yunit width\mainrule}% r\xE9glure principale de droite\xA4\idx*\vrule\xA7*\clap\xA4
+	}%
+}
+\yunit=1cm \xunit=2cm
+\leavevmode \carreau{3}{4} puis \carreau{8}{10}\xA4\idx*\leavevmode\xA4|
+
+Il suffit maintenant de mettre le tout dans une \idx\hbox. Cette boite a pour exactes dimensions \verb|\xunit| et \verb|\yunit| et il ne reste plus qu'\xE0 confier \xE0 \idx\leaders le soin de la r\xE9p\xE9ter autant de fois horizontalement et verticalement que l'on veut de carreaux dans ces deux directions :
+
+\begingroup
+\def\carreau#1#2{% #1=nb subdiv H  #2=nb subdiv V
+	% #### r\xE9glures horizontales
+	\rlap{% mettre \xE0 droite de la position sans bouger\xA4\idx*\rlap\xA4
+		\vbox to\yunit{% dans un \vbox de hauteur \yunit\xA4\idx*\vbox\xA4
+			\offinterlineskip% pas de ressort d'interligne\xA4\idx*\offinterlineskip\xA4
+			\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale\xA4\xA7*\vlap\idx*\hrule\xA4
+			\leaders% r\xE9p\xE9ter (ici ce sera donc #2-1 fois)\xA4\idx*\leaders\xA4
+				\vbox to\dimexpr\yunit/#2\relax% une \vbox de hauteur \yunit/#2\xA4\idx*\dimexpr\xA4
+					{\vss% ressort qui va s'\xE9tirer \xE0 \yunit/#2\xA4\idx*\vss\xA4
+					\vlap{\hrule height\subrule width\xunit}% r\xE9glure de subdiv de dim 0pt
+					}\vfill% ressort de \leaders\xA4\idx*\vfill\xA4
+			\kern\dimexpr\yunit/#2\relax% derniere espace verticale\xA4\idx*\kern\xA4
+			\vlap{\hrule height\mainrule width\xunit}% r\xE9glure principale\xA4\xA7*\vlap\xA4
+		}%
+	}%
+	% #### r\xE9glures verticales
+	\hbox to\xunit{% dans une \hbox de longueur \xunit\xA4\idx*\vbox\xA4
+		\clap{\vrule height\yunit width\mainrule}% r\xE9glure principale\xA4\xA7*\clap\idx*\vrule\xA4
+		\leaders% r\xE9op\xE9ter (ici ce sera donc #1-1 fois)\xA4\idx*\leaders\xA4
+			\hbox to\dimexpr\xunit/#1\relax\xA4\idx*\hbox\xA4
+				{\hss% ressort qui va s'\xE9tirer \xE0 \xunit/#1\xA4\idx*\hss\xA4
+				\clap{\vrule height\yunit width\subrule}% r\xE9glure H de dimension 0\xA4\xA7*\clap\xA4
+				}\hfill% ressort de \leaders\xA4\idx*\hfill\xA4
+			\kern\dimexpr\xunit/#1\relax% derni\xE8re espace H\xA4\idx*\kern\xA4
+			\clap{\vrule height\yunit width\mainrule}% r\xE9glure principale\xA4\idx*\vrule\xA7*\clap\xA4
+	}%
+}
+\showcode|\mainrule=0.8pt \subrule=0.2pt
+\def\grid#1#2#3#4{%\xA4\xA7*\grid\xA4
+	\vbox to#3\yunit{% dans une boite verticale de hauteur #3*\yunit\xA4\idx*\vbox\xA4
+		\leaders% r\xE9p\xE9ter verticalement\xA4\idx*\leaders\xA4
+			\hbox to#1\xunit{% une boite de longueur #1*\xunit
+				\leaders% dans laquelle se r\xE9p\xE8te horizontalement\xA4\idx*\leaders\xA4
+					\hbox{\carreau{#2}{#4}}% le carreau de largeur \xunit
+				\hfill}%\xA4\idx*\hfill\xA4
+		\vfill\xA4\idx*\vfill\xA4
+	}%
+}
+Grille 1 : \xunit=1cm \yunit=1cm \grid{5}{10}{2}{10}\smallskip\xA4\idx*\smallskip\xA4
+
+Grille 2 : \xunit=0.5cm \yunit=0.5cm \grid{7}{1}{3}{1}\smallskip\xA4\idx*\smallskip\xA4
+
+Grille 3 : \xunit=1.5cm \yunit=0.5cm \grid{4}{3}{3}{2}|
+\endgroup
+
+Bien que le r\xE9sultat soit strictement identique, la fa\xE7on de tracer le quadrillage avec \idx\leaders comme ci-dessus est tr\xE8s diff\xE9rente de celle employ\xE9e pr\xE9c\xE9demment avec la boucle \xA7\for. En effet, la m\xE9thode avec \idx\leaders est beaucoup plus \xABlaborieuse\xBB puisqu'il s'agit d'une b\xEAte r\xE9p\xE9tition d'un \xE9l\xE9ment. Le r\xE9sultat est trompeur pour l'\oe il, car la r\xE9p\xE9tition horizontale et verticale de cet \xE9l\xE9ment donne l'illusion que les r\xE9glures horizontales ou verticales sont trac\xE9es en un coup alors qu'il n'en est rien. De plus, toutes les r\xE9glures principales communes \xE0 deux carreaux-unit\xE9 adjacents sont m\xEAme superpos\xE9es et sont donc trac\xE9es deux fois. Personne ne tracerait un quadrillage \xE0 la main de cette fa\xE7on sur une feuille de papier ! \xC0 l'inverse, la m\xE9thode avec \xA7\for b\xE2tissait le quadrillage de fa\xE7on plus globale puisque les r\xE9glures avaient la dimension maximale et \xE9taient effectivement trac\xE9es en un coup, comme on le ferait spontan\xE9ment \xE0 la r\xE8gle et au crayon.
+
+\chapter{Fichiers : lecture et \xE9criture}\idx*[|(]{fichier}
+\section{Lire un fichier}\idx*[|(]{fichier!lecture}
+\subsection{La primitive \texttt{\char`\\ input}}\idx*[|(]\input
+\TeX{} peut \xAB lire un fichier \xBB, c'est-\xE0-dire qu'il peut lire le contenu du fichier, exactement comme il le fait lorsqu'il lit le code source. Pour cela, on utilise la syntaxe\footnote{Il est peut-\xEAtre utile de signaler que \LaTeX{}, aussi incroyable que cela puisse paraitre, franchit un interdit en red\xE9finissant la primitive \texttt{\string\input} pour en faire une macro (non d\xE9veloppable). Fort heureusement, la primitive est sauvegard\xE9e par \texttt{\string\let} dans la s\xE9quence de contr\xF4le \texttt{\string\@@input}.} :
+
+\centrecode-\input <nom d'un fichier>-
+
+\noindent Lorsque \TeX{} s'attend \xE0 lire le nom d'un fichier, le d\xE9veloppement maximal se met en place. Le nom du fichier s'\xE9tend jusqu'au premier espace rencontr\xE9 (et cet espace sera absorb\xE9) ou jusqu'\xE0 la premi\xE8re primitive non d\xE9veloppable : mettre un espace ou un \idx\relax apr\xE8s la fin d'un nom de fichier est donc une bonne habitude \xE0 prendre.
+
+La primitive \idx\jobname se d\xE9veloppe en le nom du fichier \xAB maitre \xBB en cours de compilation. Le fichier \xAB maitre \xBB est le fichier de plus haut niveau, celui qui n'a \xE9t\xE9 appel\xE9 par aucun \idx\input.  Le nom cr\xE9\xE9 par \idx\jobname se compose de caract\xE8res de catcode 12\idx*{catcode!12 (autre)} et ne comporte pas l'extension du fichier, c'est-\xE0-dire le \xAB\verb|.|\xBB et les caract\xE8res qui le suivent.
+
+Le fichier lu par \idx\input peut lui aussi contenir la primitive \idx\input, et ainsi de suite r\xE9cursivement dans des limites raisonnables. Une fois que la fin du fichier est atteinte ou que la primitive \verb|\endinput| est rencontr\xE9e, \TeX{} cesse la lecture du fichier et la reprend dans fichier parent o\xF9 il s'\xE9tait interrompu.
+
+\begin{regle}
+Lorsque \TeX{} lit le code source, on peut faire lire \xE0 \TeX{} le contenu d'un fichier. La lecture se fera comme se fait celle du code source et tout se passe donc comme si l'int\xE9gralit\xE9 du contenu du fichier \xE9tait ins\xE9r\xE9e dans le code source \xE0 l'endroit o\xF9 est rencontr\xE9 :
+
+\centrecode-\input <nom de fichier>-
+
+Si le \verb|<nom de fichier>| ne sp\xE9cifie pas d'extension, \TeX{} rajoute \xAB\verb|.tex|\xBB.
+
+La lecture du fichier s'arr\xEAte lorsque la fin du fichier est atteinte ou lorsque la primitive \verb|\endinput| est atteinte.
+\end{regle}
+
+\subsection{\texttt{\char`\\ input} et ses secrets}\label{input.secrets}
+Examinons maintenant les autres aspects bien plus \TeX niques de la primitive \idx\input. Cette section, assez ardue, peut \xEAtre saut\xE9e lors d'une premi\xE8re lecture.
+
+Tout d'abord, la primitive \idx\input est d\xE9veloppable lorsqu'on la 1-d\xE9veloppe, tout se passe comme si \TeX{} d\xE9tournait sa t\xEAte de lecture pour aller lire la totalit\xE9 du contenu du fichier. Il faut signaler que la totalit\xE9 du fichier est lue selon le r\xE9gime de catcode en vigueur au moment du 1-d\xE9veloppement. De la m\xEAme fa\xE7on qu'il le fait lorsqu'il lit du code source, \TeX{} ins\xE8re le caract\xE8re de code \idx\endlinechar \xE0 la fin de chaque ligne du fichier, y compris la derni\xE8re.
+
+Plusieurs choses assez \TeX niques se passent \xE0 la fin d'un fichier :
+
+\begin{enumerate}
+	\item avant la fin du fichier, \TeX{} ins\xE8re le contenu de \idx\everyeof. Cette primitive a un comportement identique \xE0 celui d'un registre de tokens et elle est vide par d\xE9faut;
+	\item juste apr\xE8s le code ins\xE9r\xE9 par \idx\everyeof, \TeX{} ex\xE9cute une routine interne.
+\end{enumerate}
+
+Cette routine interne est en r\xE9alit\xE9 un test auquel proc\xE8de \TeX{} : il v\xE9rifie que l'endroit o\xF9 il se trouve est compatible avec le statut \idx\outer\footnote{On peut le constater dans le code source \xAB\texttt{tex.web}\xBB du programme \texttt{tex} \xE0 la section \no362, le test \xAB\texttt{check\_outer\_validity}\xBB est effectu\xE9.}. Avant de poursuivre, il faut d\xE9finir ce qu'est ce statut : il concerne normalement les macros qui peuvent \xEAtre d\xE9finies comme \xE9tant \xAB\idx\outer\xBB.
+
+\label{outer}\begin{regle}
+Lorsque la primitive \idx\outer pr\xE9c\xE8de la d\xE9finition d'une macro, cette derni\xE8re ne pourra pas se situer dans les endroits o\xF9 \TeX{} lit du code \xAB \xE0 grande vitesse \xBB\idx*{lecture \xE0 grande vitesse}, \xE0 savoir :
+\begin{itemize}
+	\item le texte de remplacement ou le \idx{texte de param\xE8tre} lors de la d\xE9finition d'une macro ;
+	\item le code situ\xE9 dans les branches d'un test;
+	\item le pr\xE9ambule d'un alignement initi\xE9 par \idx\halign ou \idx\valign.
+\end{itemize}
+\end{regle}
+
+Si une telle macro se trouve dans ces endroits interdits, un message d'erreur sera \xE9mis et la compilation stopp\xE9e :
+
+\errcode/\outer\def\foo{Bonjour}
+\def\bar{\foo}/{! Forbidden control sequence found while scanning definition of \string\bar.}
+
+Une action peu connue de \idx\noexpand\verb|<token>|, lorsque \idx\noexpand est d\xE9velopp\xE9, est de d\xE9sactiver pour le \verb|<token>| le test qui v\xE9rifie si ce \verb|<token>| est \idx\outer\footnote{Cela est expliqu\xE9 \xE0 la section \no369 de \texttt{tex.web} par \textsc{Knuth} lui-m\xEAme : \xABComme des macros {\string\outer} peuvent se pr\xE9senter ici, on doit aussi r\xE9initialiser [\xE0 "\texttt{normal}"] le \texttt{scanner\_statut} temporairement.\xBB}. On peut donc l'utiliser pour enfreindre la r\xE8gle pr\xE9c\xE9dente et mettre une macro \idx\outer dans le texte de remplacement d'une autre macro :
+
+\showcode/\outer\def\foo{Bonjour}\xA4\idx*\outer\xA4
+\expandafter\def\expandafter\bar\expandafter{\noexpand\foo}\xA4\idx*\noexpand\xA4
+\meaning\bar\xA4\idx*\meaning\xA4
+
+\edef\baz{\noexpand\foo}\xA4\idx*\noexpand\xA4
+\meaning\baz/
+
+Revenons au test \xE0 la fin du fichier : comme il v\xE9rifie que l'endroit o\xF9 il se trouve est compatible avec \idx\outer, il communique \xE0 la fin du fichier le statut \idx\outer. Pour d\xE9sactiver le test, nous allons appliquer la m\xEAme m\xE9thode qu'avec une macro \idx\outer, c'est-\xE0-dire le faire pr\xE9c\xE9der de la primitive \idx\noexpand.
+
+\begin{regle}
+La fin d'un fichier a le statut \idx\outer.
+
+Pour permettre que la fin d'un fichier se situe dans un endroit normalement interdit \xE0 ce statut, il faut placer la primitive \idx\noexpand juste avant la fin du fichier, soit en l'\xE9crivant explicitement, soit via \idx\everyeof avec l'assignation
+
+\centrecode-\everyeof{\noexpand}-\idx*\everyeof
+
+\noindent et faire en sorte de d\xE9velopper ce \idx\noexpand.
+\end{regle}
+
+D\xE9velopper le \idx\noexpand rend tr\xE8s contraignante et quasi impossible la d\xE9finition d'une macro dont le texte de remplacement serait le contenu d'un fichier. En effet, pour forcer ce d\xE9veloppement \emph{avant} que la d\xE9finition de la macro ne se fasse, il faudrait la d\xE9finir avec \idx[|etc]\edef\forbidindex\edef{} selon ce sch\xE9ma :
+
+\centrecode-\begingroup
+\everyeof{\noexpand}\xA4\idx*\noexpand\xA4
+\global\edef\<macro>{\input<nom de fichier> }
+\endgroup-\idx*\global\idx*\input
+
+Cette d\xE9finition est tr\xE8s peu satisfaisante, car la primitive \idx\edef implique que le contenu du fichier est d\xE9velopp\xE9 au maximum ce qui, sauf cas tr\xE8s particulier, n'est pas ce qui est recherch\xE9. De plus, elle rend la d\xE9finition globale puisqu'un groupe semi-simple a \xE9t\xE9 ouvert pour limiter la port\xE9e de la modification de \idx\everyeof.
+
+\label{input.dans.macro}Heureusement, nous pouvons bien mieux faire. L'id\xE9e est d'ins\xE9rer un d\xE9limiteur (ici \verb|\eof at nil|) en fin de fichier via \idx\everyeof. Ce d\xE9limiteur sera captur\xE9 par une macro auxiliaire \xE0 argument d\xE9limit\xE9 qui sera d\xE8s lors capable de savoir o\xF9 se trouve la fin du fichier et affecter \xE0 une macro ce qui se trouve dans ce fichier avant ce d\xE9limiteur. Toute cette man\oe uvre suppose que le fichier ne contient pas \verb|\eof at nil|.
+
+Supposons par exemple que le fichier \xAB\texttt{test.txt}\xBB contient :
+
+\centrecode-Programmer en \TeX{} est   facile
+
+et utile-
+
+Voici comment programmer une macro \xA7*\filedef[|(]
+
+\centrecode-\filedef\<macro>{<nom du fichier>}-
+\immediate\openout\wtest=test.txt
+\exactwrite\wtest|Programmer en \TeX{} est   facile
+
+et utile|%
+\immediate\closeout\wtest
+
+\noindent qui d\xE9finit une \verb|\<macro>| dont le texte de remplacement est le contenu du fichier :
+
+\showcode/\catcode`\@11
+\long\def\filedef#1#2{%\xA4\xA7*\filedef\idx*\long\xA4
+	\begingroup
+		\let\input\@@input% <- utilisateurs de latex uniquement\xA4\idx*\input\idx*\@@input\idx*[|etc]\let\forbidindex\let\xA4
+		\everyeof{\eof at nil\noexpand}% ins\xE8re "\eof at nil\noexpand" \xE0 la fin du fichier\xA4\idx*\everyeof\idx*\noexpand\xA4
+		\expandafter\filedef at i\expandafter#1% d\xE9veloppe \input #2\xA4\defline\ccc\xA4
+			\expandafter\relax\input #2\xA4\defline\aaa\xA4
+}
+\long\def\filedef at i#1#2\eof at nil{%\xA4\idx*\long\xA4
+	\endgroup
+	\expandafter\def\expandafter#1\expandafter{\gobone#2}% mange le \relax\xA4\defline\bbb\xA4
+}
+\catcode`\@12
+\filedef\foo{test.txt}
+\meaning\foo/
+
+La ligne \xAB\verb|\let\input\@@input|\xBB redonne \xE0 \idx\input son statut de primitive et annule la red\xE9finition effectu\xE9e par \LaTeX\footnote{Ce livre a \xE9t\xE9 compil\xE9 en utilisant le format \LaTeX.}. Il est bien \xE9vident que les utilisateurs d'autres formats ne doivent pas \xE9crire cette ligne.
+
+Ensuite, \xE0 la ligne \no\aaa, un \idx\relax a \xE9t\xE9 ins\xE9r\xE9 avant le d\xE9veloppement de \idx\input. Ceci nous assure que l'argument d\xE9limit\xE9 \verb|#2| de \verb|\filedef at i| ne serait pas d\xE9pouill\xE9 de ses accolades si jamais le contenu du fichier \xE9tait constitu\xE9 d'un texte entre accolades. Ce \idx\relax est mang\xE9 \xE0 la ligne \no\bbb{} par le \verb|\gobone| avant que la d\xE9finition ne soit faite.
+
+L'important est de comprendre qu'une fois le \idx\input 1-d\xE9velopp\xE9 par le pont d'\idx\expandafter et en tenant compte du contenu de \idx\everyeof, les lignes \nos\ccc{} et \number\numexpr\ccc+1\relax{} deviennent :
+
+\centrecode-\filedef at i#1\relax<contenu du fichier lu par \input>\eof at nil\noexpand<EOF>-
+
+\noindent La macro \verb|\filedef at i|, qui ne lit que ce qui se situe jusqu'au \verb|\eof at nil|, ne verra jamais la fin du fichier \verb|<EOF>|. Le but recherch\xE9 est atteint : le \verb|<EOF>| est pr\xE9c\xE9d\xE9 d'un \idx\noexpand, et ce \idx\noexpand, en \xE9tant ex\xE9cut\xE9 apr\xE8s que \verb|\filedef at i| ait fait son travail, rendra \verb|<EOF>| compatible avec le statut \idx\outer.\idx*[|)]\input\xA7*\filedef[|)]
+
+\section{Lire dans un fichier}
+\xAB Lire un fichier \xBB n'a pas la m\xEAme signification que \xAB lire \emph{dans} un fichier \xBB qui sous-entend que l'on peut lire, contr\xF4ler ce qu'on lit et donc reprendre la main. Pour fonctionner selon ce mode, \TeX{} dispose de 16 canaux d'entr\xE9e, num\xE9rot\xE9s de 0 \xE0 15, chacun correspondant \xE0 un flux de lecture. Comme pour les boites, les compteurs, les dimensions et les registres de tokens, plain-\TeX{} fournit la macro \idx\newread\verb|\<macro>| qui assigne\footnote{Cette macro fonctionne comme son homologue \texttt{\string\newbox}. Comme il n'existe pas de primitive \texttt{\string\readdef}, la macro est d\xE9finie par la primitive \texttt{\string\chardef}.} \xE0 la \verb|\<macro>| un entier correspondant \xE0 un canal de lecture disponible.
+
+\begin{regle}
+\relax\TeX{} dispose de 15 canaux de lecture portant les num\xE9ros de 0 \xE0 15.
+
+On demande l'allocation d'un canal de lecture par
+
+\centrecode-\newread\<macro>-
+
+et ce faisant, la \verb|\<macro>| devient \xE9quivalente \xE0 un \verb|<nombre>|, qui est un num\xE9ro de canal libre. Un \verb|<canal>| est donc un \verb|<nombre>| explicitement \xE9crit ou une macro d\xE9finie avec \idx\newread.
+\medbreak
+
+Avant de lire dans un fichier, on doit d'abord lier un \verb|<canal>| \xE0 un fichier avec\idx*\openin :
+
+\centrecode-\openin<canal>= <nom du fichier>-
+
+\noindent Si aucune extension n'est pr\xE9cis\xE9e au \verb|<nom du fichier>|, \TeX{} rajoute \xAB\verb|.tex|\xBB. Le signe \verb|=| et l'espace qui le suit sont optionnels. Lorsque \TeX{} lit le \verb|<nom du fichier>|, il entre dans une phase de d\xE9veloppement maximal et si ce nom est suivi d'un espace, cet espace est absorb\xE9.
+
+Tout canal ouvert doit \xEAtre ferm\xE9 et donc, apr\xE8s avoir fait les op\xE9rations de lecture, il convient d'ex\xE9cuter \idx\closein\verb|<canal>| pour d\xE9solidariser le \verb|<canal>| du fichier qui lui avait \xE9t\xE9 attach\xE9 avec \idx\openin.
+\end{regle}
+
+Le test \tidx{ifeof}\verb|<canal>| teste si la lecture du fichier li\xE9 au \verb|<canal>| est arriv\xE9e \xE0 la fin du fichier. Employ\xE9 juste apr\xE8s avoir li\xE9 un flux \xE0 un fichier via \idx\openin, le test \verb|\ifeof<canal>| sera vrai uniquement si le fichier sp\xE9cifi\xE9 n'existe pas. Voici donc comment b\xE2tir une macro \xA7\iffileexists :
+
+\showcode/\xA4\string\newread\string\rtest\idx*\newread\xA4% canal de lecture employ\xE9 dans tout ce chapitre
+\def\iffileexists#1#2{% #1=canal de lecture  #2=nom du fichier\xA4\xA7*\iffileexists\xA4
+	\openin#1=#2\xA4\idx*\openin\xA4
+	\ifeof#1% le fichier n'existe pas\xA4\tidx*{ifeof}\xA4
+		\closein#1\xA4\idx*\closein\xA4
+		\expandafter\secondoftwo% renvoyer faux\xA4\xA7*\secondoftwo[|etc]\forbidindex\secondoftwo\xA4
+	\else
+		\closein#1
+		\expandafter\firstoftwo% sinon renvoyer vrai\xA4\xA7*\firstoftwo[|etc]\forbidindex\firstoftwo\xA4
+	\fi
+}
+a) \iffileexists\rtest{test.txt}{vrai}{faux}\qquad
+b) \iffileexists\rtest{foobar.txt}{vrai}{faux}\xA4\xA7*\iffileexists\xA4/
+
+Dans tout cet exemple, nous avons demand\xE9 l'allocation d'un \verb|<canal>| avec \xAB \idx\newread\verb|\rtest| \xBB et d\xE9sormais, nous utiliserons le canal de lecture \no\verb|\rtest| dans tous les exemples.
+\grandsaut
+
+Un fichier peut-\xEAtre lu par plusieurs canaux simultan\xE9ment. Cela signifie que si le besoin s'en fait sentir, on peut positionner des t\xEAtes de lecture dans un fichier \xE0 plusieurs endroits, chacune pouvant lire le fichier ind\xE9pendamment des autres.
+
+\begin{regle}
+Lorsqu'un \verb|<canal>| de lecture est ouvert et li\xE9 \xE0 un fichier, \TeX{} peut lire des \emph{lignes} dans ce fichier les unes apr\xE8s les autres, et assigner la ligne lue \xE0 une macro. On utilise la syntaxe\idx*\read
+
+\centrecode-\read\<canal> to \<macro>-
+
+\noindent o\xF9 le mot-cl\xE9 \xABto\xBB est obligatoire et \xE9ventuellement suivi d'espaces optionnels.
+
+Ceci a pour effet de placer dans le texte de remplacement de la \verb|\<macro>| tout ce qu'il y a dans la ligne en cours :
+
+\begin{itemize}
+	\item les accolades doivent \xEAtre \xE9quilibr\xE9es dans la ligne en cours. Si elles ne le sont pas, \TeX{} lit autant de lignes que n\xE9cessaire pour qu'elles le soient. Si la fin du fichier est atteinte sans que l'\xE9quilibrage des accolades ne soit r\xE9alis\xE9, une erreur de compilation surviendra;
+	\item une fois l'\xE9quilibrage des accolades atteint, la primitive \idx\read lit tout ce qui s'\xE9tend jusqu'\xE0 la \xABmarque de \idx{fin de ligne}\xBB (voir page~\pageref{marque.fin.ligne});
+	\item les tokens dans le texte de remplacement de la \verb|\<macro>| tiennent compte du r\xE9gime de catcode en vigueur lorsque \idx\read est ex\xE9cut\xE9e; \idx\read effectue donc une \xAB tok\xE9nisation\xBB, c'est-\xE0-dire la transformation d'\idx{octet}s bruts en tokens;
+	\item le caract\xE8re de code \idx\endlinechar est ins\xE9r\xE9 \xE0 la fin du texte de remplacement de la\verb|\<macro>|;
+	\item l'assignation est globale si \idx\read est pr\xE9c\xE9d\xE9 de \idx\global.
+\end{itemize}
+
+La primitive de \idx\eTeX{}\idx\readline, dont la syntaxe est
+
+\centrecode-\readline\<canal> to \<macro>-
+
+\noindent agit comme \idx\read sauf qu'elle ins\xE8re dans le texte de remplacement de la \verb|\<macro>| tous les tokens lus dans la ligne (y compris le caract\xE8re de code \idx\endlinechar). L'espace aura le catcode 10\idx*{catcode!10 (espace)} et tous les autres caract\xE8res le catcode 12\idx*{catcode!12 (autre)}.
+\end{regle}
+
+Pour fixer les id\xE9es, si le canal \no\verb|\rtest| est li\xE9 \xE0 un fichier et que la ligne suivante \xE0 lire dans ce fichier est :
+
+\centrecode-Programmer en \TeX{} est facile-
+
+\noindent Si l'on \xE9crit \xAB\verb-\read\rtest to \foo-\xBB, tout se passe comme si on avait fait l'assignation d'une macro sans argument :
+
+\centrecode-\def\foo{Programmer en \TeX{} est facile }-
+
+\noindent Il est important de noter que l'espace en fin de texte provient du caract\xE8re de code \idx\endlinechar : celui-ci \xE9tant par d\xE9faut \xAB\verbidx*[ (retour charriot)]{^^M}\verb|^^M|\xBB de catcode \number\catcode`\^^M {}\idx*{catcode!5 (retour charriot)}, il est lu comme un espace comme le stipule la r\xE8gle page~\pageref{regle.catcode5}. Pour mettre ce comportement en \xE9vidence dans l'exemple ci-dessous, le fichier \verb|filetest.txt| contiet :
+\immediate\openout\wtest= filetest.txt
+\exactwrite\wtest|Programmer en \TeX{} est   facile
+
+et utile|%
+\immediate\closeout\wtest
+
+\centrecode-Programmer en \TeX{} est   facile
+
+et utile-
+
+Notons qu'il y a 3 espaces entre les mots \xAB est \xBB et \xAB facile \xBB et regardons ce que donne le code suivant :
+
+\showcode|\openin\rtest =filetest.txt\xA4\idx*\openin\xA4
+\read\rtest to \foo% lit la premi\xE8re ligne\xA4\idx*\read\xA4
+1) Signification : \meaning\foo.\par% signification de ce qui a \xE9t\xE9 lu\xA4\idx*\meaning\xA4
+1) Ex\xE9cution : \foo\par
+\read\rtest to \foo% lit la deuxi\xE8me ligne
+2) Signification : \meaning\foo.\par
+2) Ex\xE9cution : \foo\par
+\read\rtest to \foo% lit la derni\xE8re ligne\xA4\idx*\read\xA4
+3) Signification : \meaning\foo.\par\xA4\idx*\meaning\xA4
+3) Ex\xE9cution : \foo
+\closein\rtest\xA4\idx*\closein\xA4|
+
+Les points apr\xE8s chaque \idx\meaning\verb|\foo| sont ici destin\xE9s \xE0 mettre en \xE9vidence l'espace en fin de texte de remplacement.
+
+Voici le m\xEAme exemple, cette fois-ci avec la primitive \idx\readline :
+
+\showcode|\openin\rtest =filetest.txt\xA4\idx*\openin\xA4
+\readline\rtest to \foo% lit la premi\xE8re ligne\xA4\idx*\readline\xA4
+1) Signification : \meaning\foo.\par% signification de ce qui a \xE9t\xE9 lu\xA4\idx*\meaning\xA4
+1) Ex\xE9cution : \foo\par
+\readline\rtest to \foo% lit la deuxi\xE8me ligne
+2) Signification : \meaning\foo.\par
+2) Ex\xE9cution : \foo\par
+\readline\rtest to \foo% lit la derni\xE8re ligne\xA4\idx*\readline\xA4
+3) Signification : \meaning\foo.\par\xA4\idx*\meaning\xA4
+3) Ex\xE9cution : \foo
+\closein\rtest\xA4\idx*\closein\xA4|
+
+Une premi\xE8re question se pose naturellement : d'o\xF9 viennent les virgules que l'on observe \xE0 la fin du texte de remplacement de \verb|\foo| ? Elles sont la preuve que le caract\xE8re de code \idx\endlinechar, plac\xE9 en fin de ligne, a \xE9t\xE9 d\xE9tok\xE9niz\xE9 par \idx\readline pour devenir un inoffensif caract\xE8re de catcode 12\idx*{catcode!12 (autre)}. On voit une virgule car \idx\endlinechar a pour valeur \number\endlinechar{} et que le caract\xE8re ayant ce code dans la \idx{fonte} utilis\xE9e est la virgule :
+
+\showcode/Valeur de \string\endlinechar = \number\endlinechar\par\xA4\idx*\string\idx*\number\idx*\endlinechar\xA4
+Caract\xE8re correspondant : << \char\endlinechar{} >>\xA4\idx*\char\xA4/
+
+Le second point qui peut surprendre est qu'au premier cas, le texte de remplacement de \verb|\foo| contient \emph{tous les espaces} (ils sont 3) entre les mots \xABest\xBB et \xABfacile\xBB, alors qu'un seul \xE9tait lu par \idx\read. La subtile diff\xE9rence entre \idx\read et \idx\readline est que cette derni\xE8re ignore les catcodes en cours et ins\xE8re dans le texte de remplacement de la macro \emph{tous} les caract\xE8res lus dans la ligne; elle ins\xE8re donc \emph{tous} les espaces, en leur donnant un catcode de 10.
+
+\begin{exercice}
+Proposer une m\xE9thode pour que la macro \idx\read ne lise que ce qui se trouve dans la ligne courante, \emph{sans} y ajouter le caract\xE8re de code \idx\endlinechar.
+
+Appliquer cette m\xE9thode pour \xE9crire une macro \xA7\xread[|(] qui agit de la m\xEAme fa\xE7on que \idx\read avec la m\xEAme syntaxe :
+
+\centrecode|\xread<canal> to \<macro>|
+
+mais qui place dans le texte de remplacement de la \verb|\<macro>| le contenu de la ligne sans le caract\xE8re de code \idx\endlinechar.
+\solution
+Il suffit d'op\xE9rer localement et d\xE9finir le \idx\endlinechar \xE0 $-1$ et utiliser un \idx\global pour que la 
+\verb|\<macro>| survive \xE0 la fermeture du groupe :
+
+\showcode|\openin\rtest =filetest.txt\xA4\idx*\openin\xA4
+Ligne 1 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la premi\xE8re ligne\xA4\idx*\endlinechar\idx*\global\idx*\read\xA4
+\meaning\foo.\par% donne ce qui a \xE9t\xE9 lu\xA4\idx*\meaning\xA4
+Ligne 2 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la deuxi\xE8me ligne
+\meaning\foo.\par
+Ligne 3 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la derni\xE8re ligne\xA4\idx*\endlinechar\idx*\global\idx*\read\xA4
+\meaning\foo.\xA4\idx*\meaning\xA4
+\closein\rtest\xA4\idx*\closein\xA4|
+
+Contrairement \xE0 l'exemple pr\xE9c\xE9dent, comme le caract\xE8re de code \idx\endlinechar n'est pas ins\xE9r\xE9 \xE0 la fin des lignes, la seconde ligne est bien lue comme \xE9tant vide.
+
+Pour la macro \verb|\xread|, nous n'allons pas utiliser de \idx\global car il est toujours plus s\xFBr de se passer, lorsque c'est possible, d'assignations globales qui provoquent des effets de bord difficiles \xE0 maitriser. Nous allons tout d'abord sauvegarder  dans la macro \verb|\restoreendlinechar| le code qui permet de restaurer \idx\endlinechar. Cette macro aura comme texte de remplacement
+
+\centrecode-\endlinechar=<valeur actuelle de \endlinechar>-
+
+Toute la difficult\xE9 vient ensuite des espaces optionnels qui se trouvent apr\xE8s le mot-cl\xE9 \xAB\verb|to|\xBB. En effet, si nous d\xE9clarons la macro \xA7\xread ainsi
+
+\centrecode-\def\xread#1to#2{<code \xE0 d\xE9finir>}-
+
+\noindent rien ne permet d'affirmer que l'argument \verb|#2| sera la \verb|\<macro>| : si des espaces optionnels sont \xE9crits apr\xE8s \xAB\verb|to|\xBB, alors \verb|#2| sera un espace. Il va donc falloir tester l'argument \verb|#2| et ne le prendre en compte que lorsqu'il sera une s\xE9quence de contr\xF4le, ce qui suppose la mise en place d'une macro r\xE9cursive. Pour mener \xE0 bien le test, nous mettrons en \oe uvre la macro \xA7\ifcs programm\xE9e \xE0 la page~\pageref{ifcs.la.vraie}.
+
+\showcode/\def\xread#1to#2{%
+	\ifcs{#2}% si #2 est une s\xE9quence de contr\xF4le
+		{\edef\restoreendlinechar{\endlinechar=\the\endlinechar}%
+		\endlinechar=-1 % supprime le caract\xE8re mis en fin de ligne
+		\read#1to#2% lit la ligne et l'assigne \xE0 la macro #2
+		\restoreendlinechar\relax% restaure le \endlinechar
+		}% si #2 n'est pas une s\xE9quence de contr\xF4le,
+		{\xread#1to}% ignorer #2, et recommencer 
+}
+
+\openin\rtest =filetest.txt\xA4\idx*\openin\xA4
+Ligne 1 : \xread\rtest to \foo% lit la premi\xE8re ligne
+\meaning\foo.\par% donne ce qui a \xE9t\xE9 lu\xA4\idx*\meaning\xA4
+Ligne 2 : \xread\rtest to \foo% lit la deuxi\xE8me ligne
+\meaning\foo.\par
+Ligne 3 : \xread\rtest to \foo% lit la derni\xE8re ligne
+\meaning\foo.\xA4\idx*\meaning\xA4
+\closein\rtest\xA4\idx*\closein\xA4/
+
+Une premi\xE8re remarque consiste \xE0 dire que la syntaxe de \xA7\xread n'est \emph{pas exactement identique} \xE0 celle de \idx\read. En effet, la macro r\xE9cursive \xA7\xread ignore les arguments \verb|#2| tant qu'ils ne sont pas une s\xE9quence de contr\xF4le. L'appel farfelu suivant est donc tout \xE0 fait valide :
+
+\centrecode-\xread\rtest toW a aZcd 1 2345\foo-
+
+Mais surtout, il existe une m\xE9thode bien plus \xE9l\xE9gante pour programmer \xA7\xread, non r\xE9cursive, ayant exactement la m\xEAme syntaxe que \idx\read, mais qui fait intervenir la primitive \idx\afterassignment que nous verrons plus tard (voir page~\pageref{afterassignment}). Le code est donn\xE9 \xE0 titre indicatif :
+
+\showcode|\def\xread{% doit \xEAtre suivie de "<nombre> to \<macro>"
+	\edef\restoreendlinechar{\endlinechar=\the\endlinechar}%\xA4\idx*\endlinechar\idx*\the\xA4
+	\endlinechar=-1 % neutralise \endlinechar
+	\afterassignment\restoreendlinechar% apr\xE8s l'assignation, restaurer \endlinechar\xA4\idx*\afterassignment\xA4
+	\read% attend <nombre> to \<macro> pour effectuer l'assignation\xA4\idx*\read\xA4
+}
+\catcode`\@12
+
+\openin\rtest =filetest.txt\xA4\idx*\openin\xA4
+Ligne 1 : \xread\rtest to \foo% lit la premi\xE8re ligne
+\meaning\foo.\par% donne ce qui a \xE9t\xE9 lu\xA4\idx*\meaning\xA4
+Ligne 2 : \xread\rtest to \foo% lit la deuxi\xE8me ligne
+\meaning\foo.\par
+Ligne 3 : \xread\rtest to \foo% lit la derni\xE8re ligne
+\meaning\foo.\xA4\idx*\meaning\xA4
+\closein\rtest\xA4\idx*\closein\xA4|\xA7*\xread[|)]
+\end{exercice}
+
+\subsection{Faire une recherche dans un fichier}
+Envisageons maintenant un cas pratique et imaginons qu'une liste de fournitures soit contenue dans un fichier \xAB\verb|founitures.txt|\xBB dont le contenu est le suivant :
+
+\immediate\openout\wtest= fournitures.txt
+\immediate\write\wtest{Ref,Item,Prix,Fournisseur^^J%
+1201a,article 1,25.90,\noexpand\TeX{} marchand ^^J%
+4562u,article 2,120,fournisseur 1^^J%
+1721d,article 3,57.10,fournisseur 2}%
+\immediate\closeout\wtest
+\centrecode|Ref,Item,Prix,Fournisseur
+1201a,article 1,25.90,\TeX{} marchand
+4562u,article 2,120,fournisseur 1
+1721d,article 3,57.10,fournisseur 2
+<etc>|
+
+On remarque que la premi\xE8re ligne du fichier n'est pas \xE0 proprement parler une ligne de donn\xE9es, elle indique le nom des champs qui composent les lignes suivantes.
+
+Supposons que ce fichier soit dans le m\xEAme r\xE9pertoire\footnote{Ou qu'un lien symbolique vers ce fichier soit pr\xE9sent dans le r\xE9pertoire de compilation.} que le fichier maitre et que nous souhaitions chercher dans ce fichier une ligne par sa r\xE9f\xE9rence, c'est-\xE0-dire par ce qui est contenu dans le premier champ. Le but est de mettre au point une macro \xA7\searchitem appel\xE9e de cette fa\xE7on
+
+\centrecode-\searchitem<canal>{fournitures.txt}{1721d}\foo-\xA7*\searchitem
+
+\noindent de telle sorte que la ligne o\xF9 se trouve le premier champ \xAB\verb|1721d|\xBB soit trouv\xE9e. La macro purement d\xE9veloppable \verb|\foo|\verb|{<champ>}| sera cr\xE9\xE9e o\xF9 son argument pr\xE9cisera de quel \verb|<champ>| on souhaite obtenir la valeur. Par exemple,
+
+\begin{centrage}\small
+	\begin{tabular}{r@{\quad affiche \quad}l}
+		\verb|\foo{ref}|&1721d\\
+		\verb|\foo{item}|&article 3\\
+		\verb|\foo{prix}|&57.10\\
+		\verb|\foo{fournisseur}|&fournisseur 2
+	\end{tabular}
+\end{centrage}
+
+La macro \verb|\foo| est ici prise pour l'exemple, mais naturellement, le choix du nom de cette macro est \xE0 la convenance de l'utilisateur.
+
+Fixons-nous trois contraintes suppl\xE9mentaires :
+
+\begin{itemize}
+	\item si le fichier n'existe pas ou si la r\xE9f\xE9rence cherch\xE9e n'existe pas, la macro \verb|\foo| d\xE9finie doit \xEAtre \idx\let-\xE9gale \xE0 \verb|\gobone|. De cette fa\xE7on, elle absorbera son argument et ne produira aucun affichage;
+	\item si un champ n'existe pas, rien ne doit \xEAtre affich\xE9. Par exemple, \verb|\foo{truc}| ne doit produire aucun affichage;
+	\item lors de la recherche, toute ligne vide doit \xEAtre ignor\xE9e.
+\end{itemize}
+
+La premi\xE8re chose \xE0 faire va \xEAtre d'initialiser la macro \verb|\foo| (argument \verb|#4|) sera initialis\xE9e \xE0 \verb|\gobone|. Ensuite, la premi\xE8re ligne du fichier sera lue, ses champs seront parcourus avec \xA7\doforeach afin de stocker leur nom \xE9crit en lettres minuscules dans une macro \verb|\fieldname<i>| ou \verb|<i>| est le num\xE9ro du champ.
+
+Par la suite, nous pourrons commencer \xE0 lire les lignes de donn\xE9es : chaque ligne sera envoy\xE9e \xE0 une macro auxiliaire \verb|\test at field| charg\xE9e d'examiner leurs champs. Le premier champ de la ligne en cours sera compar\xE9 \xE0 celui qui est recherch\xE9 et si le test est positif, il incombera \xE0 la macro \verb|\test at filed| de proc\xE9der aux assignations n\xE9cessaires des macros
+
+\begin{itemize}
+	\item \verb|\foo.<nom du champ 1>|%{\ttfamily\textbackslash\boxtoken{foo.\codeelement{nom du champ 1}}}
+	\item \verb|\foo.<nom du champ 2>|{\ttfamily\textbackslash\boxtoken{foo.\codeelement{nom du champ 2}}}
+	\item etc
+\end{itemize}
+
+\noindent chacune \verb|\let|-\xE9gale \xE0 \verb|\fieldname<i>|.
+
+Enfin, la macro purement d\xE9veloppable \verb|\foo|, prenant comme argument un \verb|<champ>|, sera cr\xE9\xE9e. Elle testera avec \tidx{ifcsname} si la macro \verb|\foo.<champ>| existe, auquel cas elle formera cette macro via \idx\csname.
+
+\showcode|\def\macroname{% se d\xE9veloppe en le nom de la macro qui suit sans \xA4\xA7*\macroname\xA4
+               % le caract\xE8re d'\xE9chappement
+	\ifnum\escapechar>-1 % si le caract\xE8re d'\xE9chappement est positif\xA4\idx*\escapechar\xA4
+		\ifnum\escapechar<256 % et inf\xE9rieur \xE0 256, d\xE9velopper les 2 "\fi"
+			\expandafter\expandafter\expandafter\expandafter% et le "\string", puis
+			\expandafter\expandafter\expandafter\gobone% manger le "\" avec \gobone
+		\fi
+	\fi
+	\string% doit \xEAtre suivi d'une macro\xA4\idx*\string\xA4
+}
+\catcode`\@11
+\newcount\field at cnt
+\def\searchitem#1#2#3#4{% #1= canal  #2=nom fichier #3=r\xE9f\xE9rence  #4=macro \xE0 d\xE9finir\xA4\xA7*\searchitem\xA4
+	\let#4\gobone% pour l'instant, #4=\gobone
+	\openin#1=#2\relax\xA4\idx*\openin\xA4
+	\unless\ifeof#1% si le fichier existe\xA4\tidx*{unless}\tidx*{ifeof}\xA4
+		\lowercase{\def\sought at firstfield{#3}}% stocke le 1er champ \xE0 chercher\xA4\idx*\lowercase\xA4
+		\edef\macro at name{\macroname#4}% nom de la macro sans "\"\xA4\xA7*\macroname\xA4
+		\xread#1 to \current at line% lire la premi\xE8re ligne\xA4\xA7*\xread\xA4
+		\field at cnt=0 % initialiser le compteur de champs
+		% ################ sauvegarde du nom des champs ################
+		\expsecond{\doforeach\current at field\in}\current at line% pour chaque champ\xA4\xA7*\expsecond\xA4
+			{\advance\field at cnt1 % incr\xE9menter le compteur de champs\xA4\idx*\advance\xA4
+			\lowercase\expandafter{% e texte de remplacement de \current at field en minuscule\xA4\idx*\lowercase\xA4
+				\expandafter\def\expandafter\current at field\expandafter{\current at field}%
+			}%
+			% sauvegarder chaque champ de la 1re ligne (qui sont les intitul\xE9s) dans une macro
+			\letname{fieldname\number\field at cnt}=\current at field\xA4\xA7*\letname\xA4
+			}%
+		\edef\field at num{\number\field at cnt}% nombre de champs
+		% ################ lecture des lignes de donn\xE9es ################
+		\loop% tant que...\xA4\idx*\loop\xA4
+			\unless\ifeof#1\relax% ...la fin du fichier n'est pas atteinte\xA4\tidx*{unless}\tidx*{ifeof}\xA4
+				\xread#1 to \current at line% lire une ligne\xA4\xA7*\xread\xA4
+				\unless\ifx\current at line\empty% si elle n'est pas vide\xA4\idx*\empty\xA4
+					% examniner les champs qu'elle contient (aller \xE0 \test at field)
+					\expsecond{\expandafter\test at field\current at line\@nil}\macro at name%\xA4\defline\aaa \xA7*\expsecond\xA4
+				\fi
+		\repeat\xA4\idx*\repeat\xA4
+	\fi
+	\closein#1\relax\xA4\idx*\closein\xA4
+}
+
+\def\test at field#1,#2\@nil#3{% #1=champ no 1 #2=autres champs #3=nom de la macro sans "\"
+	\def\current at firstfield{#1}% stocke le premier champ de la ligne en cours
+	\ifx\current at firstfield\sought at firstfield% s'il est \xE9gal \xE0 celui cherch\xE9
+		\defname{#3.\csname fieldname1\endcsname}{#1}% d\xE9finir la macros \<#3."champ 1">\xA4\xA7*\defname\xA4
+		\field at cnt=1 % initialiser le compteur de champ
+		\doforeach\current at field\in{#2}% puis, pour i>2, d\xE9finir les macros \<#3."champ i">\xA4\xA7*\doforeach\xA4
+			{\advance\field at cnt1 % incr\xE9menter le compteur de champ
+			\letname{#3.\csname fieldname\number\field at cnt\endcsname}=\current at field\xA4\xA7*\letname\xA4
+			}%
+		\defname{#3}##1{% et d\xE9finir la macro \<#3>\xA4\xA7*\defname\xA4
+			\ifcsname#3.##1\endcsname% si la macro \<#3."argument"> existe d\xE9j\xE0\xA4\tidx*{ifcsname}\xA4
+				\csname#3.##1\expandafter\endcsname% l'ex\xE9cuter apr\xE8s avoir mang\xE9 le \fi
+			\fi
+		}%
+	\fi
+}
+\catcode`\@12
+
+\searchitem\rtest{fournitures.txt}{4562u}\monarticle\xA4\xA7*\searchitem\xA4
+r\xE9f = \monarticle{ref},
+d\xE9nomination = \monarticle{item},
+prix = \monarticle{prix},
+fournisseur = \monarticle{fournisseur},
+champ non existant = \monarticle{foobar}.
+
+\searchitem\rtest{fournitures.txt}{truc}\essai% r\xE9f\xE9rence "truc" n'existe pas\xA4\xA7*\searchitem\xA4
+r\xE9f = \essai{ref},
+d\xE9nomination = \essai{item},
+prix = \essai{prix},
+fournisseur = \essai{fournisseur}.|
+
+La macro \xA7\macroname, donn\xE9e tout au d\xE9but, doit \xEAtre suivie d'une \verb|\<macro>| et se d\xE9veloppe en le nom de cette \verb|\<macro>| sans l'\xE9ventuel caract\xE8re d'\xE9chappement.
+
+\begin{exercice}
+Programmer une am\xE9lioration de la macro \xA7\searchitem pour que la recherche puisse se faire sur n'importe quel champ. Les champs seront sp\xE9cifi\xE9s par leur num\xE9ro et non plus par leur nom. La syntaxe sera :
+
+\centrecode-\searchitem<canal>{<nom fichier>}{<num\xE9ro champ>=<valeur>}\<macro>-
+
+La modification de la syntaxe concerne le 3\ieme{} argument et l'introduction du \verb|<num\xE9ro champ>| que l'on souhaite chercher. Si ce \verb|<num\xE9ro champ>| et le signe \verb|=| sont absent, le \verb|<num\xE9ro champ>| sera pris \xE9gal \xE0 1.
+
+On supposera que le fichier \xAB\verb|basecourse.txt|\xBB recueille les donn\xE9es des participants \xE0 une course \xE0 pied et contient :
+\immediate\openout\wtest= basecourse.txt
+\exactwrite\wtest|Nom,Pr\xE9nom,Classement,Naissance,Licenci\xE9,Temps
+Demay,Pierre,237,27/8/1986,oui,2h37
+Leblanc,Nicolas,187,4/9/1978,non,2h05
+Valet,Bruno,78,25/11/1989,oui,1h47
+Hachel,Andr\xE9,283,2/3/1972,non,2h42
+Jalabert,Jean,165,19/1/1982,Oui,2h01|%
+\immediate\closeout\wtest
+
+\centrecode-Nom,Pr\xE9nom,Classement,Naissance,Licenci\xE9,Temps
+Demay,Pierre,237,27/8/1986,oui,2h37
+Leblanc,Nicolas,187,4/9/1978,non,2h05
+Valet,Bruno,78,25/11/1989,oui,1h47
+Hachel,Andr\xE9,283,2/3/1972,non,2h42
+Jalabert,Jean,165,19/1/1982,Oui,2h01-
+
+Si l'on \xE9crit
+
+\centrecode-\searchitem\rtest{basecourse.txt}{3=283}\coureur-
+
+alors, \xA7\searchitem doit chercher la ligne o\xF9 le 3\ieme{} champ vaut 283. Par la suite, la macro \verb|\coureur| doit admettre un argument \emph{num\xE9rique} \verb|<i>| et \verb|\coureur{<i>}| doit renvoyer la valeur du champ \no\verb|<i>|. Par exemple, \verb|\coureur{2}| doit renvoyer \xABAndr\xE9\xBB.
+\solution
+Les modifications \xE0 apporter ne sont pas tr\xE8s nombreuses.
+
+Tout d'abord, il faut lire la premi\xE8re ligne et l'ignorer : elle n'est d'aucune utilit\xE9. Ensuite, il faut traiter correctement l'argument \verb|#3| selon qu'il contient le signe \verb|=| ou pas. \xC0 l'issue de ce traitement, on a stock\xE9 le num\xE9ro du champ et sa valeur dans 2 macros pour les utiliser plus tard.
+
+Dans le code pr\xE9c\xE9dent, la boucle \idx\loop \xE9tait parcourue jusqu'\xE0 ce que \tidx{ifeof} soit vrai. Une petite am\xE9lioration consiste \xE0 permettre une sortie pr\xE9matur\xE9e si la ligne est trouv\xE9e. Pour cela, un bool\xE9en cr\xE9\xE9 avec \idx\newif sera initialis\xE9 \xE0 vrai et mis \xE0 faux s'il faut sortir de la boucle \idx\loop :
+
+\begin{itemize}
+	\item soit lorsque le test \tidx{ifeof} est vrai;
+	\item soit parce que la ligne a \xE9t\xE9 trouv\xE9e.
+\end{itemize}
+
+\showcode/\def\macroname{% se d\xE9veloppe en le nom de la macro qui suit sans \xA4\xA7*\macroname\xA4
+               % le caract\xE8re d'\xE9chappement
+	\ifnum\escapechar>-1 % si le caract\xE8re d'\xE9chappement est positif\xA4\idx*\escapechar\xA4
+		\ifnum\escapechar<256 % et inf\xE9rieur \xE0 256, d\xE9velopper les 2 "\fi"
+			\expandafter\expandafter\expandafter\expandafter% et le "\string", puis
+			\expandafter\expandafter\expandafter\gobone% manger le "\" avec \gobone
+		\fi
+	\fi
+	\string% doit \xEAtre suivi d'une macro\xA4\idx*\string\xA4
+}
+\catcode`\@11
+\newcount\field at cnt
+\newif\ifsearch at repeat\xA4\idx*\newif\xA4
+\def\assign at arg#1=#2\@nil{%
+	\def\sought at fieldnumber{#1}% no du champ \xE0 chercher
+	\def\sought at fielvalue{#2}% et sa valeur
+}
+\def\searchitem#1#2#3#4{% #1= canal  #2=nom fichier #3=champ cherch\xE9  #4=macro \xE0 d\xE9finir\xA4\xA7*\searchitem\xA4
+	\let#4\gobone% pour l'instant, #4=\gobone
+	\openin#1=#2\relax%\xA4\idx*\openin\xA4
+	\unless\ifeof#1% si le fichier existe\xA4\tidx*{unless}\tidx*{ifeof}\xA4
+		\edef\macro at name{\macroname#4}% nom de la macro sans "\"\xA4\xA7*\macroname\xA4
+		\xread#1 to \current at line% lire et ignorer la premi\xE8re ligne\xA4\xA7*\xread\xA4
+		\ifin{#3}{=}% si #3 contient =\xA4\xA7*\ifin\xA4
+			{\assign at arg#3\@nil}% trouver le no de champ et sa valeur
+			{\def\sought at fieldnumber{1}% sinon, no du champ = 1
+			\def\sought at fielvalue{#3}% et sa valeur = #3
+			}%
+		% ################ lecture des lignes de donn\xE9es ################
+		\search at repeattrue% poursuite de la boucle loop : vraie
+		\loop% tant que...\xA4\idx*\loop\xA4
+			\ifeof#1\relax% ...la fin du fichier n'est pas atteinte\xA4\tidx*{unless}\tidx*{ifeof}\xA4
+				\search at repeatfalse% sortir de la boucle loop
+			\else
+				\xread#1 to \current at line% lire une ligne\xA4\xA7*\xread\xA4
+				\unless\ifx\current at line\empty% si elle n'est pas vide\xA4\idx*\empty\xA4
+					% examniner les champs qu'elle contient (aller \xE0 \test at field)
+					\expsecond{\expandafter\test at field\current at line\@nil}\macro at name%\xA4\defline\aaa \xA7*\expsecond\xA4
+				\fi
+			\fi
+			\ifsearch at repeat% ne poursuivre que si le bool\xE9en en vrai
+		\repeat\xA4\idx*\repeat\xA4
+	\fi
+	\closein#1\relax\xA4\idx*\closein\xA4
+}
+
+\def\test at field#1\@nil#2{% #1=champs #2=nom de la macro sans "\"
+	\field at cnt=0 % initialiser le compteur de champ
+	\doforeach\current at field\in{#1}% parcourir les champs de la ligne en cours\xA4\xA7*\doforeach\xA4
+		{\advance\field at cnt1 % incr\xE9menter le compteur de champ
+		\ifnum\field at cnt=\sought at fieldnumber\relax% si c'est le bon num\xE9ro de champ
+			\ifx\current at field\sought at fielvalue% et si le champ correspond \xE0 celui cherch\xE9
+				\search at repeatfalse% sortir de la boucle loop
+				\doforeachexit% sortir de la boucle \doforeach en cours\xA4\xA7*\doforeachexit\xA4
+			\fi
+		\fi
+		}%
+	\unless\ifsearch at repeat% si la ligne a \xE9t\xE9 trouv\xE9e
+		\field at cnt=0 % initialiser le compteur de champ
+		\doforeach\current at field\in{#1}% parcourir \xE0 nouveau les champs de la ligne\xA4\xA7*\doforeach\xA4
+				{\advance\field at cnt1 % incr\xE9menter le compteur de champ
+				\letname{#2.\number\field at cnt}=\current at field% faire l'assignation\xA4\xA7*\letname\xA4
+				}%
+		\defname{#2}##1{% et d\xE9finir la macro \<#2>\xA4\xA7*\defname\xA4
+			\ifcsname#2.##1\endcsname% si la macro \<#2."argument"> existe d\xE9j\xE0\xA4\tidx*{ifcsname}\xA4
+				\csname#2.##1\expandafter\endcsname% l'ex\xE9cuter apr\xE8s avoir mang\xE9 le \fi
+			\fi
+		}%
+	\fi
+}
+\catcode`\@12
+a) \searchitem\rtest{basecourse.txt}{3=283}\foo
+   "\foo1", "\foo2", "\foo3", "\foo4", "\foo5", "\foo6", "\foo7"
+
+b) \searchitem\rtest{basecourse.txt}{Valet}\bar
+   "\bar1", "\bar2", "\bar3", "\bar4", "\bar5", "\bar6", "\bar{abcd}"/
+\end{exercice}
+
+\subsection{Afficher le contenu exact d'un fichier}
+Nous allons maintenant programmer une macro \xA7\showfilecontent[|(] de syntaxe
+
+\centrecode-\showfilecontent<canal>{<nom du fichier>}-
+
+\noindent qui affiche le contenu du fichier pass\xE9 en argument, en police \xE0 chasse fixe. Le but est d'imiter pour les fichiers la primitive \idx\meaning qui donne le texte de remplacement d'une macro.
+
+Il va falloir agir sur les codes de cat\xE9gorie avec les macros \idx\do et \idx\dospecials de plain-\TeX{} pour rendre tous les tokens inoffensifs, sauf l'espace qui sera rendu actif avec \idx\obeyspaces.
+
+Le fichier \xAB\verb|readtext.txt|\xBB utilis\xE9 dans l'exemple contient 3 lignes :
+
+\centrecode-Programmer en \TeX{} est   facile
+
+et utile-
+
+\immediate\openout\wtest=readtest.txt
+\exactwrite\wtest|Programmer en \TeX{} est   facile
+
+et utile|%
+\immediate\closeout\wtest
+
+\showcode|\def\showfilecontent#1#2{% #1=canal de lecture #2=nom de fichier\xA4\xA7*\showfilecontent\xA4
+	\begingroup
+		\tt% s\xE9lectionner la fonte \xE0 chasse fixe\xA4\idx*\tt\xA4
+		\openin#1=#2\relax\xA4\idx*\openin\xA4
+		\ifeof#1% si la fin du fichier est d\xE9j\xE0 atteinte, il n'existe pas et\xA4\tidx*{ifeof}\xA4
+			Le fichier n'existe pas% afficher le message
+		\else% le fichier existe
+			\def\do##1{\catcode`##1=12 }%\xA4\idx*\do\xA4
+			\dospecials% neutraliser tous les tokens sp\xE9ciaux\xA4\idx*\dospecials\xA4
+			\obeyspaces% rendre l'espace actif\xA4\idx*\obeyspaces\defline\bbb\xA4
+			\loop\xA4\idx*\loop\xA4
+				\xread#1 to \currline% lire une ligne\xA4\xA7*\xread\xA4
+				\unless\ifeof#1% si la fin du fichier n'est pas atteinte\xA4\tidx*{unless}\tidx*{ifeof}\xA4
+				\leavevmode\par% aller \xE0 la ligne\xA4\idx*\leavevmode\defline\aaa\xA4
+				\currline% afficher la ligne lue
+			\repeat% recommencer\xA4\idx*\repeat\xA4
+		\fi
+		\closein#1\relax\xA4\idx*\closein\xA4
+	\endgroup
+}
+
+Contenu du fichier : "\showfilecontent\rtest{readtest.txt}", affich\xE9 tel quel|
+
+Il est int\xE9ressant de noter qu'un \idx\obeyspaces est \xE9crit \xE0 la ligne \no\bbb{} car
+
+\centrecode-\letactive\ =\space-\xA7*\letactive\idx*\space{}
+
+\noindent ne fonctionnerait pas puisque que \xA7\letactive, tout comme \xA7\defactive, \emph{n\xE9cessite} que le caract\xE8re \xAB\verb|~|\xBB soit actif. Or, ce n'est plus le cas ici puisque \idx\dospecials l'a rendu de catcode 12.
+
+En revanche, placer \verb|\letactive\ =\space|\xA7*\letactive\idx*\space{} avant le \idx\dospecials aurait fonctionn\xE9.
+
+\begin{exercice}
+Expliquer pourquoi le guillemet initial ne se situe pas juste avant le mot \xAB\verb|D\xE9but|\xBB et proposer une solution pour que cela soit le cas.
+\solution
+Chaque ligne affich\xE9e, contenue dans la macro \verb|\currline|, est pr\xE9c\xE9d\xE9e de \idx\leavevmode\idx\par (ligne \no\aaa), y compris pour la premi\xE8re ligne lue. De par la structure de la macro \xA7\showfilecontent, un \idx\par est donc toujours ins\xE9r\xE9 entre le guillemet initial et le premier caract\xE8re du fichier.
+
+Une solution originale est de garder \xAB\verb|\leavevmode\par|\xBB sauf que l'on va mettre une macro \xABmagique\xBB \xA7\magicpar en lieu et place de \idx\par. Cette macro aux vertus sp\xE9ciales doit n'avoir aucun effet pour l'affichage la premi\xE8re fois et ex\xE9cuter un \idx\par les autres fois. Pour r\xE9pondre \xE0 ces contraintes, \xA7\magicpar doit se modifier elle-m\xEAme en \idx\par la premi\xE8re fois qu'elle sera ex\xE9cut\xE9e. Voici comment la d\xE9finir :
+
+\centrecode-\def\magicpar{\let\magicpar=\par}-
+
+Avec une telle d\xE9finition, \xA7\magicpar ne va rien afficher la premi\xE8re fois qu'elle sera ex\xE9cut\xE9e, mais va silencieusement se red\xE9finir pour devenir \xE9gale \xE0 \idx\par. Nous avons bien cr\xE9\xE9 une macro locale au groupe semi-simple, qui est neutre pour l'affichage la premi\xE8re fois et \xE9quivalente \xE0 \idx\par ensuite.
+
+\showcode|\def\showfilecontent#1#2{% #1=canal de lecture #2=nom de fichier\xA4\xA7*\showfilecontent\xA4
+	\begingroup
+		\tt% s\xE9lectionner la fonte \xE0 chasse fixe\xA4\idx*\tt\xA4
+		\openin#1=#2\relax\xA4\idx*\openin\xA4
+		\ifeof#1% si la fin du fichier est d\xE9j\xE0 atteinte, il n'existe pas et
+			Le fichier n'existe pas% afficher le message
+		\else% le fichier existe
+			\def\do##1{\catcode`##1=12 }%\xA4\idx*\do\xA4
+			\dospecials% neutraliser tous les tokens sp\xE9ciaux\xA4\idx*\dospecials\xA4
+			\obeyspaces% rendre l'espace actif\xA4\idx*\obeyspaces\xA4
+			\def\magicpar{\let\magicpar=\par}%\xA4\xA7*\magicpar\xA4
+			\loop\xA4\idx*\loop\xA4
+				\xread#1 to \currline% lire une ligne\xA4\xA7*\xread\xA4
+				\unless\ifeof#1% si la fin du fichier n'est pas atteinte\xA4\tidx*{unless}\tidx*{ifeof}\xA4
+				\leavevmode\magicpar% former le paragraphe (sauf \xE0 la 1er it\xE9ration)\xA4\idx*\leavevmode\xA4
+				\currline% afficher la ligne
+			\repeat% recommencer\xA4\idx*\repeat\xA4
+		\fi
+		\closein#1\relax\xA4\idx*\closein\xA4
+	\endgroup
+}
+
+Contenu du fichier : "\showfilecontent\rtest{readtest.txt}", affich\xE9 tel quel|
+\end{exercice}\xA7*\showfilecontent[|)]\idx*[|)]{fichier!lecture}
+
+\section{\xC9crire dans un fichier}\idx*[|(]{fichier!\xE9criture}
+\subsection{La primitive \texttt{\textbackslash write}}\idx*[|(]\write
+Il est facile de deviner par sym\xE9trie que si \TeX{} dispose de 16 canaux pour lire un fichier, il en dispose aussi de 16 pour \xE9crire dans un fichier. Et le pendant de la macro \idx\newread est \xE9videmment \idx\newwrite, qui en partage la syntaxe et qui alloue globalement un canal d'\xE9criture libre.
+
+\begin{regle}
+\relax\TeX{} dispose de 15 canaux d'\xE9criture portant les num\xE9ros de 0 \xE0 15.
+
+On demande l'allocation d'un canal d'\xE9criture par\idx*\newwrite
+
+\centrecode-\newwrite\<macro>-
+
+et ce faisant, la \verb|\<macro>| devient \xE9quivalente \xE0 un \verb|<nombre>|, qui est un num\xE9ro de canal libre. Un \verb|<canal>| est donc un \verb|<nombre>| explicitement \xE9crit ou une macro d\xE9finie avec \idx\newwrite.
+\medbreak
+
+Avant d'\xE9crire dans un fichier, on doit d'abord lier un \verb|<canal>| \xE0 un fichier avec\idx*\openout :
+
+\centrecode-\openout<canal>= <nom du fichier>-
+
+\noindent et lorsque les op\xE9rations d'\xE9criture sont termin\xE9es, on d\xE9solidarise le \verb|<canal>| du fichier par \idx*\closeout
+
+\centrecode-\closeout<canal>= <nom du fichier>-
+
+\noindent Une ligne vide est ins\xE9r\xE9e en fin de fichier.
+
+Pour \xE9crire une ligne dans le fichier, on \xE9crit :
+
+\centrecode-\write<canal>{<texte>}-
+
+\noindent o\xF9 le \verb|<texte>| est un code dans lequel les accolades sont \xE9quilibr\xE9es. L'\xE9criture dans le fichier n'a pas lieu lorsque la commande \idx\write est rencontr\xE9e, mais lorsque la page courante est compos\xE9e. Le \verb|<texte>| est stock\xE9 dans la m\xE9moire de \TeX{} et est d\xE9velopp\xE9 au maximum lorsque \TeX{} \xE9crit dans le fichier. Si l'utilisateur souhaite bloquer le d\xE9veloppement, il lui appartient de le bloquer \xE0 l'aide des m\xE9thodes vues \xE0 la page~\pageref{bloquer.developpement.maximum}.
+\grandsaut
+
+Les op\xE9rations li\xE9es \xE0 l'\xE9criture dans un fichier (\idx\openout, \idx\write et \idx\closeout) ont la particularit\xE9 d'avoir lieu lorsque la page est compos\xE9e, c'est-\xE0-dire plus tard dans le temps que lorsque les instructions sont rencontr\xE9es. Ce d\xE9calage temporel est bien utile lorsqu'on souhaite \xE9crire un \idx{num\xE9ro de page} puisque l'on s'assure que le bon num\xE9ro de page sera \xE9crit, mais il est ind\xE9sirable pour \xE9crire des donn\xE9es non sensibles au positionnement dans le document. Pour s'affranchir de cette d\xE9synchronisation temporelle, il faut faire pr\xE9c\xE9der \idx\openout, \idx\write et \idx\closeout de la primitive \xAB \idx\immediate \xBB qui force les op\xE9rations d'\xE9criture \xE0 \xEAtre faites imm\xE9diatement lorsqu'elles sont rencontr\xE9es.
+\end{regle}
+
+Dans tout le reste du chapitre, nous utiliserons le canal d'\xE9criture \verb|\wtest| que nous allons allouer avec \idx\newwrite\verb|\wtest|.
+
+Voici deux tentatives successives d'\xE9criture dans un m\xEAme fichier :
+
+\showcode|\xA4\string\newwrite\string\wtest\xA4% sera le canal d'\xE9criture dans tout ce chapitre\xA4\idx*\newwrite\xA4
+\immediate\openout\wtest=writetest.txt % lie \wtest au fichier\xA4\idx*\immediate\idx*\openout\xA4
+\immediate\write\wtest{Programmer en \noexpand\TeX{} est   facile.}% \xE9crit une ligne\xA4\idx*\write\idx*\noexpand\xA4
+\immediate\write\wtest{Et utile...}% puis une autre
+\immediate\closeout\wtest% d\xE9fait la liaison\xA4\idx*\closeout\xA4
+a) Contenu du fichier :\par
+"\showfilecontent\rtest{writetest.txt}"% affiche le contenu du fichier\xA4\xA7*\showfilecontent\xA4
+\medbreak\xA4\idx*\medbreak\xA4
+% 2e tentative :\xA4\defline\aaa\xA4
+b) Contenu du fichier :\par
+\immediate\openout\wtest=writetest.txt % lie \wtest au fichier
+\immediate\write\wtest{Essai d'\xE9criture}% \xE9crit une ligne\xA4\idx*\write\xA4
+\immediate\closeout\wtest% d\xE9fait la liaison\xA4\idx*\immediate\xA4
+"\showfilecontent\rtest{writetest.txt}"% affiche le contenu du fichier\xA4\xA7*\showfilecontent\xA4|
+
+Remarquons \xE0 partir de la ligne \no\aaa, que si on lie un canal \xE0 un fichier d\xE9j\xE0 existant et que l'on \xE9crit \xE0 nouveau dans ce fichier, le contenu pr\xE9c\xE9dent est effac\xE9, c'est-\xE0-dire que l'\xE9criture recommence au d\xE9but du fichier.
+
+Remarquons \xE9galement que l'argument de \idx\write est lu par \TeX{} avant d'\xEAtre d\xE9tok\xE9niz\xE9 et \xE9crit dans le fichier. La perte d'informations lorsque \TeX{} lit du code source a donc lieu. Ici en particulier, les espaces cons\xE9cutifs dans \xAB\verb*|est   facile|\xBB ont \xE9t\xE9 lus comme un seul espace et \xE9crits comme tel dans le fichier.
+
+Enfin, il faut noter que \idx\write, lorsqu'il d\xE9tok\xE9nize le \verb|<texte>|, rajoute un espace apr\xE8s les s\xE9quences de contr\xF4le.
+
+\subsection{Programmer des variantes de \texttt{\textbackslash write}}
+\subsubsection{La macro \texttt{\char`\\noexpwrite}}\xA7*\noexpwrite
+Si la primitive \idx\write d\xE9veloppe au maximum ce qu'elle va \xE9crire, il est logique de construire un \xE9quivalent qui lui, ne proc\xE8dera \xE0 aucun d\xE9veloppement. Parmi des m\xE9thodes \xE0 notre disposition pour bloquer le d\xE9veloppement, la plus pratique est de recourir \xE0 \idx\unexpanded :
+
+\showcode/\def\noexpwrite#1#2{% #1=num\xE9ro de canal  #2=texte \xE0 \xE9crire\xA4\xA7*\noexpwrite\xA4
+	\write#1{\unexpanded{#2}}%\xA4\idx*\write\idx*\unexpanded\xA4
+}
+\immediate\openout\wtest=writetest.txt \xA4\idx*\openout\xA4
+\immediate\noexpwrite\wtest{Programmer en \TeX{} est   facile.}%\xA4\idx*\immediate\xA4
+\immediate\noexpwrite\wtest{Et utile...}%\xA4\xA7*\noexpwrite\xA4
+\immediate\closeout\wtest\xA4\idx*\closeout\xA4
+Contenu du fichier :\par
+\showfilecontent\rtest{writetest.txt}% affiche le contenu du fichier\xA4\xA7*\showfilecontent\xA4/
+
+Ici encore, comme l'argument \verb|#2| a \xE9t\xE9 lu par la macro \xA7\noexpwrite, les m\xEAmes pertes d'information que pr\xE9c\xE9demment ont eu lieu. Le seul moyen d'\xE9crire dans le fichier ce qu'il y a \emph{exactement} dans le code source est de proc\xE9der comme avec la macro \xA7\litterate (voir page~\pageref{litterate}).
+
+\subsubsection{La macro \texttt{\char`\\exactwrite}}\label{exactwrite}\xA7*\exactwrite[|(]
+Nous allons cr\xE9er l'\xE9quivalent de la macro \xA7\litterate pour l'\xE9criture dans un fichier, c'est-\xE0-dire une macro qui \xE9crit dans un fichier \emph{tous} les caract\xE8res qu'on lui donne \xE0 lire. Appelons cette macro \xA7\exactwrite et par commodit\xE9, sa syntaxe va ressembler \xE0 celle de \xA7\litterate. La primitive \idx\immediate sera appel\xE9e et donc l'\xE9criture sera synchrone. On suppose qu'un \verb|<canal>| a d\xE9j\xE0 \xE9t\xE9 li\xE9 au fichier dans lequel on veut \xE9crire. La syntaxe sera :
+
+\centrecode-\exactwrite{<canal><car><texte><car>-
+
+\noindent Ici, \verb|<car>| sera un caract\xE8re choisi par l'utilisateur qui servira de d\xE9limiteur au \verb|<texte>| que l'on veut \xE9crire dans le fichier, avec la limitation classique que \verb|<car>| doit \xEAtre choisi de telle sorte qu'il ne figure pas dans le \verb|<texte>|.
+
+On va proc\xE9der comme avec \xA7\litterate en rendant inoffensifs des tokens en mettant leurs catcodes \xE0 12, sauf qu'ici, cela va concerner \emph{tous} les octets, de 0 \xE0 255. C'est certes un rem\xE8de de cheval, mais de cette fa\xE7on, tous les caract\xE8res peuvent \xEAtre \xE9crits sur un fichier et ce quels que soient l'\idx{encodage} du fichier source et le r\xE9gime de catcode en cours.
+
+La m\xE9thode va \xEAtre la suivante :
+
+\begin{algo}
+	\item lire le \verb|<canal>|;
+	\item ouvrir un groupe, mettre le catcode de tous les octets \xE0 12;
+	\item lire le \verb|<car>| (qui sera de catcode 12 \xE0 cause du point pr\xE9c\xE9dent) ;
+	\item isoler le \verb|<texte>| qui se trouve jusqu'au prochain \verb|<car>|;
+	\item si ce \verb|<texte>| contient le retour charriot \xAB\verb|^^M|\verbidx*[ (retour charriot)]{^^M}\xBB (de catcode 12) :
+	\begin{algo}
+		\item \xE9crire dans le fichier le texte se trouvant avant \verb|^^M|;
+		\item retourner en 5) avec en prenant \verb|<texte>| \xE9gal \xE0 ce qu'il y a pr\xE8s \verb|^^M|;
+	\end{algo}
+	\item sinon \xE9crire le \verb|<texte>| dans le fichier et fermer le groupe.
+\end{algo}
+
+Pour forcer les catcodes de tous les octets \xE0 12, une simple boucle \xA7\for suffit :
+
+\centrecode-\for\xx=0 to 255 \do{\catcode\xx=12 }-
+
+\noindent Ensuite, comme \xE0 partir du point \no3, tout ce qui est lu est constitu\xE9 de caract\xE8res de catcode 12, il va falloir d\xE9finir un retour charriot de catcode 12\idx*{catcode!12 (autre)} qui nous servira de d\xE9limiteur d'argument. On peut s'y prendre ainsi :
+
+\centrecode-{\catcode`\^^M=12 \gdef\EOL at char{^^M}}-\idx*\gdef
+
+Dans les grandes lignes, la t\xE2ches vont se r\xE9partir de la fa\xE7on suivante. Les points \nos1 et 2 sont d\xE9volus \xE0 la macro chapeau \xA7\exactwrite. Une macro auxiliaire \verb|\exactwrite at i| va lire le \verb|<car>|, forc\xE9ment de catcode 12, qui sera son unique argument. Une fois qu'elle s'est empar\xE9 de ce \verb|<car>|, elle peut d\xE9finir une sous-macro \verb|\exactwrite at ii| dont l'argument d\xE9limit\xE9 par ce \verb|<car>| sera le \verb|<texte>| qu'elle transmettra \xE0 la macro r\xE9cursive \verb|\exactwrite at iii| qui se chargera des points \no5 \xE0 6.
+
+\showcode/\catcode`\@11
+\def\exactwrite#1{% #1=num\xE9ro de canal\xA4\xA7*\showfilecontent\xA4
+	\begingroup
+		\def\canal at write{#1}% sauvegarde le num\xE9ro de canal
+		\for\xx=0 to 255\do{\catcode\xx=12 }% donne \xE0 tous les octets le catcode 12\xA4\xA7*\for\idx*{catcode!12\space(autre)}\xA4
+		\exactwrite at i% aller lire le <car>
+}
+
+\def\exactwrite at i#1{% #1 est le <car> de catcode 12
+	\def\exactwrite at ii##1#1{% ##1 est le <texte> \xE0 envoyer vers le fichier
+		\exactwrite at iii##1\@nil% envoyer <texte> \xE0 \exactwrite at iii
+	}%
+	\exactwrite at ii% va lire tout ce qui se trouve jusqu'au prochain <car>
+}
+
+{\catcode`\^^M 12 \gdef\EOL at char{^^M}}% d\xE9finit le caract\xE8re <EOL> de catcode 12\xA4\verbidx*[ (retour charriot)]{^^M}\idx*\gdef\xA4
+
+\def\exactwrite at iii#1\@nil{% #1 = <texte> \xE0 \xE9crire dans le fichier
+	\expsecond{\ifin{#1}}\EOL at char% si #1 contient "retour charriot"\xA4\xA7*\expsecond\xA7*\ifin\xA4
+		{\write at line#1\@nil% \xE9crire la premi\xE8re ligne de #1
+		}
+		{\immediate\write\canal at write{#1}% sinon : derni\xE8re ligne atteinte, l'\xE9crire\xA4\idx*\immediate\idx*\write\xA4
+		\endgroup% puis sortir du groupe
+		}%
+}
+
+% les \expandafter provoquent le 1-d\xE9veloppement de \EOL at char :
+\expandafter\def\expandafter\write at line\expandafter#\expandafter1\EOL at char#2\@nil{%
+	\immediate\write\canal at write{#1}% \xE9crit la ligne (ce qui se trouve avant ^^M)\xA4\idx*\immediate\idx*\write\xA4
+	\exactwrite at iii#2\@nil% recommencer avec ce qui se trouve apr\xE8s "^^M"
+}
+\catcode`\@12
+
+\immediate\openout\wtest=writetest.txt % lie le canal \wtest au fichier\xA4\idx*\immediate\idx*\openout\xA4
+\exactwrite\wtest|Programmer en \TeX{} est   facile !
+
+Et tr\xE8s utile.|
+\immediate\closeout\wtest% et fermer le fichier
+
+Le contenu du fichier "writetest.txt" est :\par
+"\showfilecontent\rtest{writetest.txt}"\xA4\xA7*\showfilecontent\xA4/\idx*[|)]\write
+
+Plus pr\xE9cis\xE9ment, voici comment un \xE9diteur de fichiers\footnote{Programme dont la principale fonctionnalit\xE9 est de lire les octets d'un fichier un par un, de les afficher ainsi que les caract\xE8res ASCII correspondants s'ils sont affichables.} voit le fichier g\xE9n\xE9r\xE9 :
+
+\begin{centrage}
+	\ttfamily\footnotesize
+	\setbox0\hbox{0}
+	\edef~{\hbox to\the\wd0{\hss\noexpand\small\noexpand\textbullet\hss}}
+	\catcode`\:12 \catcode`\!12
+	\obeyspaces
+	\catcode`\/0
+	\catcode`\{12 \catcode`\}12
+	\catcode`\[1 \catcode`\]2
+	\catcode`\\12
+	/tabular[r|l|l]%
+		0000&50 72 6F 67  72 61 6D 6D  65 72 20 65  6E 20 5C 54&Programmer en \T/\%
+		0010&65 58 7B 7D  20 65 73 74  20 20 20 66  61 63 69 6C&eX{} est   facil/\%
+		0020&65 20 21 0A  0A 45 74 20  74 72 E8 73  20 75 74 69&e !~~Et tr\xE8s uti/\%
+		0030&6C 65 2E 0A                                       &le.~%
+	/endtabular%
+/end[centrage]%
+
+L'affichage se divise en trois parties, \xE0 gauche l'\xABoffset\xBB (en hexad\xE9cimal), c'est-\xE0-dire le num\xE9ro d'ordre du premier \idx{octet} de la ligne (le premier octet du fichier portant le num\xE9ro 0), au centre les octets contenus dans le fichier en notation hexad\xE9cimale et \xE0 droite les caract\xE8res correspondant aux octets (dans un codage sur un octet, le plus souvent \latin). Les caract\xE8res non affichables sont repr\xE9sent\xE9s par \xAB {\small\textbullet} \xBB. Constatons en premier lieu que le caract\xE8re \xAB\xE8\xBB est cod\xE9 sur \emph{un seul} \idx{octet} (qui est \Hex{E8}) puisque l'\idx{encodage} utilis\xE9 dans le code source de ce livre est \latin\footnote{Si l'encodage avait \xE9t\xE9 \utf, le caract\xE8re \xAB\xE8\xBB aurait \xE9t\xE9 cod\xE9 sur deux octets : \Hex{C3} \Hex{A8}}. Remarquons aussi que les seuls caract\xE8res non affichables portent le code de caract\xE8re \Hex{0A} qui est 13 en d\xE9cimal; ce sont donc les retours charriot. Il est normal d'avoir un retour charriot en fin de fichier, car comme nous l'avons vu, \TeX{} ins\xE8re une ligne vide en fin de fichier.\xA7*\exactwrite[|)]
+
+\subsection{Utilisation pratique}
+Mettons \xE0 profit ce que nous savons pour \xE9crire une macro \xA7\exo[|(], utile pour r\xE9diger des exercices et afficher leur bar\xE8me. Supposons que \xAB\verb|\exo{3.5pt}|\xBB soit ex\xE9cut\xE9e. Elle devra afficher le texte suivant :
+
+\medbreak
+\noindent\vrule height1ex width1ex depth0pt\kern1ex\textbf{Exercice 3}\leaders\hbox to5pt{\hss.\hss}\hfill3.5pt/15
+\medbreak
+
+\noindent o\xF9 \xAB15\xBB est le total des points de toutes les macros \xA7\exo du document.
+
+Remarquons que la macro \verb|\exo| a \xE9t\xE9 appel\xE9e 2 fois auparavant puisque cet appel g\xE9n\xE8re le texte de l'exercice \no3.
+
+La principale difficult\xE9 est que le total n'est pas connu lorsque la macro \verb|\exo| est ex\xE9cut\xE9e puisque d'\xE9ventuels autres appels de cette macro qui sont \xE0 venir dans le code. C'est donc un cas o\xF9 il va falloir se servir d'un fichier auxiliaire pour transmettre ce total entre deux compilations avec la contrepartie que lors d'une compilation :
+\begin{itemize}
+	\item le fichier n'existe pas, ce qui signifierait qu'il s'agit de la premi\xE8re compilation du document ou que le fichier auxiliaire a \xE9t\xE9 effac\xE9. Dans ce cas, il faudra afficher un total qui repr\xE9sente cette situation particuli\xE8re, par exemple \xAB\#\#\xBB;
+	\item le total est faux parce que depuis la derni\xE8re compilation, l'auteur du document a modifi\xE9 le bar\xE8me d'un ou plusieurs exercices ou a chang\xE9 le nombre d'exercices.
+\end{itemize}
+
+\noindent Dans ces cas, il faudra lancer \emph{deux} compilations successives pour obtenir le total correct.
+\grandsaut
+
+Avant tout, appelons \verb|\total at points| la macro dont le texte de remplacement sera soit \xAB\verb|##|\xBB, soit le total des points. Il reste \xE0 prendre une d\xE9cision; comment pouvons-nous stocker dans un fichier le total des points au fur et \xE0 mesure que le document est compil\xE9 ? Nous pouvons proc\xE9der en 3 temps :
+
+\begin{enumerate}
+	\item au d\xE9but du document, appeler une macro \verb|\initexo| qui va tester si le fichier auxiliaire existe.
+	\begin{itemize}
+		\item dans l'affirmative, elle va ex\xE9cuter le code qu'il contient avec \idx\input. Ce code d\xE9finira la macro \verb|\total at points| avec le bar\xE8me de la pr\xE9c\xE9dente compilation;
+		\item sinon, elle va placer dans le texte de remplacement de \verb|\total at points| le code \xAB\verb|\char`\#\char`\#|\xBB qui affiche \xAB\char`\#\char`\#\xBB.
+	\end{itemize}
+
+	\item elle va ouvrir ce fichier en \xE9criture y ins\xE9rer les caract\xE8res \xAB\verb|\exocalctotal|\xBB. Puis \xE0 chaque fois que la macro \verb|\exo{<bar\xE8me>}| est rencontr\xE9e, ajouter les caract\xE8res \xAB\verb|+<bar\xE8me>|\xBB au fichier;
+	\item \xE0 la fin du document, la macro \verb|\stopexo| \xE9crira \xAB\verb|\relax\endtotal|\xBB dans le fichier et le fermera.
+\end{enumerate}
+
+Admettons par exemple que \xAB\verb|\exo{5pt}|\xBB, \xAB\verb|\exo{3.5pt}|\xBB et \xAB\verb|\exo{3pt}|\xBB sont rencontr\xE9es dans le document. Alors, \xE0 la fin de la compilation (et au d\xE9but de la suivante), le fichier auxiliaire contiendra :
+
+\centrecode-\exocalctotal+5pt+3.5pt+3pt\relax\endtotal-
+
+Il nous reste \xE0 dire un mot sur la macro \verb|\exocalctotal|. Elle sera d\xE9finie pour que son argument soit d\xE9limit\xE9 par \verb|\endtotal| et son texte de remplacement placera dans la macro \verb|\total at points| la somme de tous les points. Pour ce faire, \idx\dimexpr et \xA7\dimtodec seront employ\xE9es, avec les \xE9ventuels inconv\xE9nients concernant les erreurs d'arrondis qui peuvent survenir (voir page~\pageref{arrondis.sur.dimensions}) :
+
+\centrecode-\def\exocalctotal#1\endtotal{\edef\total at points{\dimtodec\dimexpr#1}}-
+
+Le fichier contenant les points sera nomm\xE9 comme le fichier maitre (nom qui est le d\xE9veloppement de \idx\jobname), mais avec l'extension \xAB\verb|.pts|\xBB
+
+\catcode`\W12
+\showcode W\catcode`\@11
+\newcount\exo at number% compteur pour le num\xE9ro d'exercice\xA4\idx*\newcount\xA4
+
+\def\exocalctotal#1\endtotal{\edef\total at points{\dimtodec\dimexpr#1}}\xA4\xA7*\dimtodec\xA4
+
+\def\initexo#1{%
+	\def\exo at canal{#1}% sauvegarde le canal d'\xE9criture
+	\exo at number=0 % initialiser le compteur d'exo
+	\iffileexists\exo at canal{\jobname.pts}% si le fichier .pts existe\xA4\xA7*\iffileexists\idx*\jobname\xA4
+		{\input \jobname.pts }% le lire et ex\xE9cuter son contenu\xA4\idx*\input\idx*\jobname\xA4
+		{\def\total at points{\char`\#\char`\#}}% sinon, d\xE9finir un total alternatif\xA4\idx*\char\xA4
+	\immediate\openout\exo at canal=\jobname.pts % ouvrir le fichier .pts\xA4\idx*\immediate\idx*\jobname\idx*\openout\xA4
+	\immediate\write\exo at canal{\noexpand\exocalctotal}% et commencer \xE0 y \xE9crire dedans\xA4\idx*\noexpand\idx*\write\xA4
+}
+
+\def\exo#1{% d\xE9finti la macro qui affiche l'exercice
+	\bigbreak% sauter une grande espace verticale
+	\immediate\write\exo at canal{+#1}% \xE9crire "+#1" dans le fichier .pts\xA4\idx*\immediate\idx*\write\xA4
+	\advance\exo at number by 1 % incr\xE9menter le num\xE9ro de l'exercice\xA4\idx*\advance\xA4
+	\noindent\vrule height1ex width1ex depth0pt % trace le carr\xE9\xA4\idx*\noindent\idx*\vrule\xA4
+	\kern1ex% ins\xE9rer une espace horizontale\xA4\idx*\kern\xA4
+	{\bf Exercice \number\exo at number}% afficher "Exercice <nombre>"\xA4\idx*\bf\idx*\number\xA4
+	\leaders\hbox to.5em{\hss.\hss}\hfill% afficher les pointill\xE9s\xA4\idx*\leaders\idx*\hbox\idx*\hss\xA4
+	#1/\total at points%  puis #1/<total>
+	\smallbreak% composer la ligne pr\xE9c\xE9dente et sauter une espace verticale\xA4\idx*\smallbreak\xA4
+}
+
+\def\stopexo{%
+	\immediate\write\exo at canal{\relax\noexpand\endtotal}%\xA4\idx*\immediate\idx*\write\idx*\noexpand\xA4
+	\immediate\closeout\exo at canal\xA4\idx*\closeout\xA4
+}
+\catcode`\@12
+\initexo\wtest
+

@@ Diff output truncated at 1234567 characters. @@


More information about the tex-live-commits mailing list