Discussion:
Problème d'imbrication de if
(trop ancien pour répondre)
GL
2008-09-05 13:42:18 UTC
Permalink
Bonjour,

Le suivant fonctionne :

\documentclass{minimal}

\makeatletter
\newif\***@openright\@openrighttrue
\def\sideoption{\ifx\iftrue\***@openright openright\else openany\fi}
\makeatother

\begin{document}
\meaning\sideoption
\sideoption
\end{document}
\endinput


Le suivant ne fonctionne pas (Incomplete \ifx - all text was ignore...)

\documentclass{minimal}
\makeatletter

\ifx\chapter\@undefined
\relax
\else
\def\sideoption{\ifx\iftrue\***@openright openright\else openany\fi}
\fi
\makeatother

\begin{document}
\meaning\sideoption
\sideoption
\end{document}
\endinput

Je comprend pas...
BriCaMatH
2008-09-05 22:32:00 UTC
Permalink
Il y a 3 tests «\if...» il doit donc y avoir 3 «\fi» !
De toutes façons, vous vous y prenez mal car \iftrue n'est pas une
séquence de contrôle qui vaut quelque chose comme «true» et qui peut
être comparée à un autre test via un \ifx.

Le test \iftrue est un test à part entière qui s'emploie de la façon
habituelle :
\iftrue
ce teste sera toujours affiché
\else
ce texte ne sera jamais affiché
\fi
Post by GL
Le suivant ne fonctionne pas (Incomplete \ifx - all text was ignore...)
\documentclass{minimal}
\makeatletter
\relax
\else
\fi
\makeatother
\begin{document}
\meaning\sideoption
\sideoption
\end{document}
\endinput
Je comprend pas...
Bon, je ne suis pas très calé, j'observe que si le test est placé après
le \begin{document}, cela fonctionne. Manuel nous expliquera sans doute
pourquoi, je suis curieux de connaître l'explication moi aussi ;)
De plus, si \chapter n'est pas défini, \sideoption ne sera jamais
définie. Si vous invoquez \sideoption cela donnera forcément une erreur.

Je vous propose l'exemple suivant (le code est horrible et très
répétitif, mais c'est pour la bonne cause) qui envisage les 4
possibilités selon que \chapter est défini ou non et \***@openright vaut
«true» ou «false».

Enfin, dernière question : pourquoi n'employez vous pas \@ifundefined ou
même \ifdefined de eTeX ?

Christian

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{minimal}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\begin{document}
\makeatletter
\def\sideoption{}% initialisation
\newif\***@openright
\@openrightfalse

% chapitre n'est pas définit
% \***@openright vaut faux
\ifx\chapter\@undefined
\relax
\else
\def\sideoption{\***@openright openright\else openany\fi}
\fi
\meaning\sideoption\par
\string\sideoption\ donne : \sideoption\par\medskip

\@openrighttrue
% chapitre n'est pas définit
% \***@openright vaut vrai
\ifx\chapter\@undefined
\relax
\else
\def\sideoption{\***@openright openright\else openany\fi}
\fi
\meaning\sideoption\par
\string\sideoption\ donne : \sideoption\par\medskip

\def\chapter{jexiste}
\@openrightfalse
% chapitre est défini
% \***@openright vaut faux
\ifx\chapter\@undefined
\relax
\else
\def\sideoption{\***@openright openright\else openany\fi}
\fi
\meaning\sideoption\par
\string\sideoption\ donne : \sideoption\par\medskip

\@openrighttrue
% chapitre est définit
% \***@openright vaut vrai
\ifx\chapter\@undefined
\relax
\else
\def\sideoption{\***@openright openright\else openany\fi}
\fi
\meaning\sideoption\par
\string\sideoption\ donne : \sideoption\par\medskip
\makeatother
\end{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--
*BriCàMatH*, des documents pour le collège

http://www.bricamath.net <http://www.bricamath.net>
mpg
2008-09-06 16:32:10 UTC
Permalink
Post by BriCaMatH
Il y a 3 tests «\if...» il doit donc y avoir 3 «\fi» !
Rhâa, pour une fois je suis pas d'accord, Christian. Tout le sel est
justement que selon les circonstances, TeX s'attend à voir un \fi ou trois.
Post by BriCaMatH
De toutes façons, vous vous y prenez mal
Là je suis à nouveau d'accord.
Post by BriCaMatH
car \iftrue n'est pas une
séquence de contrôle qui vaut quelque chose comme «true» et qui peut
être comparée à un autre test via un \ifx.
Là plus.
Là d'accord :-)
Post by BriCaMatH
Manuel nous expliquera sans doute
pourquoi, je suis curieux de connaître l'explication moi aussi ;)
Ça m'ennuierait de te faire mentir, voilà donc les détails :-)

Déjà, \ifx\iftrue\***@openright est un test parfaitement valide : \iftrue a
un \meaning comme toute séquence de contrôle qui se respecte (et comme
toute primitive qui se respecte, son \meaning, c'est elle-même à savoir
\iftrue). \***@openright a aussi un \meaning (fut-il undefined) et comme
\ifx compare les \meaning des deux lexèmes qui le suivent, tout va pour le
mieux dans le meilleur des mondes.

Maintenant en effet, si on est sûr que \***@openright est définit (et que
c'est bien un \if dans le sens où il vaut bien \iffalse ou \iftrue), alors
il vaut bien écrire : \***@openright que \ifx\iftrue\***@openright.

Concernant l'équilibrage, c'est là que ça se gâte. En temps normal
(c'est-à-dire quand il n'est pas en train de « sauter » une branche d'un
\if), TeX s'attend à trouver autant de \fi qu'il a développé de \if.
Toujours en temps normal, quand TeX examine \ifx\iftrue\***@openright, il
commence par développer le \ifx, ce qui consomme les deux lexèmes suivants,
qui en particulier ne seront pas développés. Donc il li suffit d'un \fi
après pour revenir à l'équilibre.

Par contre, quand il est en train de « sauter » la branche à ignorer d'un
\if, TeX n'exécute ni ne développe quoi que ce soit. Il lit les lexèmes, et
regarde juste leur \meaning un par un. Et il compte les lexèmes qui dont le
\meaning est un \if quelconque, et vérifie qu'il sont équilibrés avec ceux
dont le \meaning est \fi. C'est là que ça se gâte : dans le deuxième
exemple, \ifx\iftrue\***@openright est examiné dans ce mode, donc les deux
derniers \if ne sont pas avalés par le développement du précedant (pour
cause : il n'est pas développé), et TeX compte bien 3 \if, pour seulement
un \fi, et c'est le drame.

C'est pour parer à ce genre de problème que l'on a inventé ce qu'on appelle
souvent les if à la LaTeX : les deux branches sont des arguments. Ici :

\@ifundefined{chapter}{%
\relax
}{%
\def\sideoption{\ifx\iftrue\***@openright openright\else openany\fi}%
}

ne pose pas de souci.

Une autre astuce de sioux pour gérer ses problèmes d'équilibrage de \if est
de jouer du \csname et de \expandafter :

\expandafter\ifx
\csname iftrue\expandafter\endcsname
\csname ***@openright\endcsname

marche dans les deux cas.

Manuel.
mpg
2008-09-06 16:37:49 UTC
Permalink
Post by mpg
Post by BriCaMatH
De toutes façons, vous vous y prenez mal
Là je suis à nouveau d'accord.
Encore devrais-je préciser : subtilement mal. Parce qu'en l'absence de ce
truc pervers d'équilibrage, l'idée de tester d'un coup si \***@openright est
défini et vrai était plutôt bonne (si c'était bien l'idée). Mais vu comment
TeX gère les \if, il faudrait vraiment mieux d'abord s'assurer que
\***@openright est défini, et ensuite l'utiliser tout seul pour éviter les
problèmes.

Manuel.
GL
2008-09-08 23:57:32 UTC
Permalink
Post by mpg
Post by mpg
Post by BriCaMatH
De toutes façons, vous vous y prenez mal
Là je suis à nouveau d'accord.
Encore devrais-je préciser : subtilement mal. Parce qu'en l'absence de ce
défini et vrai était plutôt bonne (si c'était bien l'idée). Mais vu comment
TeX gère les \if, il faudrait vraiment mieux d'abord s'assurer que
problèmes.
Manuel.
oui c'était bien l'idée. Moi je me représente \ifx comme une macro
_primitive_ définie comme : \def\ifx#1#2{....}
A partir de là, naturellement :
\ifx\iftrue\***@openright ... \else ... \fi
semble avoir du sens (pas de déséquilibre \if\fi)

En revanche, naturellement :
\expandafter\ifx\iftrue\***@openright ... \fi
va faire gueuler TeX (missing \fi)

Enfin, dans :
\ifx\chapter\@undefined
\relax
\else
\def\sideoption{\ifx\iftrue\***@openright openright\else openany\fi}
\fi
TeX ne comprend pas (et moi non plusse) car il analyse le premier \fi
comme pendant à \iftrue (\***@openright n'étant déclaré) et le second
comme correspondant au *deuxième* \ifx

Avec celà, il se moque totalement du \def et des accolades.

Bref, c'est un peu casse <biiip> et je comprends pourquoi LaTeX fait
toujours des blocs : \***@openright\@firstoftwo\else\@secondoftwo\fi
mpg
2008-09-09 00:19:49 UTC
Permalink
Post by GL
oui c'était bien l'idée. Moi je me représente \ifx comme une macro
_primitive_ définie comme : \def\ifx#1#2{....}
Une « macro primitive », ça s'appelle une oxymore :-)

Et ça ne marche pas comme avec \def\ifx#1#2 parce qu'on ne peut pas écrire

\ifx{abcedf}{abcdef}

(on aimerait bien pourtant, des fois).
Post by GL
Avec celà, il se moque totalement du \def et des accolades.
Oui, il se moque se tout sauf ce qui a pour \meaning un des 17 \if primitifs
de TeX (20 avec e-TeX, un peu plus avec pdfTeX) ou \fi.
Post by GL
Bref, c'est un peu casse <biiip> et je comprends pourquoi LaTeX fait
Avec les \expandafter :-)

\***@openright
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi

Manuel.
GL
2008-09-12 16:57:41 UTC
Permalink
Post by mpg
Post by GL
Bref, c'est un peu casse <biiip> et je comprends pourquoi LaTeX fait
Avec les \expandafter :-)
\else
\fi
Manuel.
En fait, dans mon fichier .sty standard, j'ai :
\newcommand\pagenumberdisplay{%
\***@frontmatter\thepage
\else\thepage / \pageref{LastPage}
\fi}
avec le package "lastpage".

Bien pour les book, mais les articles, les lettres etc. n'ont pas de
\frontmatter, \mainmatter, \backmatter.
Donc je définit quelle que soit la classe mes :
\***@frontmatter\***@mainmatter\***@backmatter

Alors que je préfèrerais faire :
\newcommand\pagenumberdisplay{%
\@ifundefined{frontmatter}{\thepage}{%
\***@frontmatter\thepage%
\else\thepage / \pageref{LastPage}%
\fi}}
mais ça plante (extra \fi) quand \frontmatter (et donc \***@frontmatter)
ne sont pas définis...

Voilà mon souci.
Et j'ai pas envie d'utiliser "ifthenelse"...
Jean-Côme Charpentier
2008-09-12 23:07:36 UTC
Permalink
Post by GL
\newcommand\pagenumberdisplay{%
\else\thepage / \pageref{LastPage}
\fi}
avec le package "lastpage".
Bien pour les book, mais les articles, les lettres etc. n'ont pas de
\frontmatter, \mainmatter, \backmatter.
C'est exact. Et toutes ces classes n'ont pas de \***@frontmatter (ce
qui est un peu dommage mais c'est comme ça).
De quelle façon ?
Post by GL
\newcommand\pagenumberdisplay{%
\else\thepage / \pageref{LastPage}%
\fi}}
ne sont pas définis...
Ben oui. Si \***@frontmatter n'existe pas, TeX ne prend pas cela pour
un \if donc gueule à propos d'un \fi qui ne ferme pas de \ifxxx (il
gueule aussi sur le \else). C'est normal, logique, toussa.
Post by GL
Voilà mon souci.
Et j'ai pas envie d'utiliser "ifthenelse"...
J'ai du mal à comprendre. Si vous voulez utiliser \***@frontmatter, il
faut bien le définir, non ? Et si possible lui donner la valeur adéquate
en fonction des commandes \frontmatter, \mainmatter et \backmatter
rencontrées dans le document.
En prenant \***@mainmatter qui est le seul défini par défaut, je n'ai
aucun problème avec l'exemple suivant :

\documentclass{book} % ou report ou article
\usepackage[T1]{fontenc}
\usepackage[latin1]{inputenc}
\usepackage[a4paper]{geometry}
\usepackage{lmodern}
\usepackage{lastpage}
\usepackage[frenchb]{babel}

\makeatletter
\newcommand\pagenumberdisplay{%
\@ifundefined{frontmatter}{\thepage}{%
\***@mainmatter
\thepage{} / \pageref{LastPage}%
\else
\thepage%
\fi
}%
}
\makeatother

\begin{document}
\pagenumberdisplay\par
Du texte.
\newpage
\pagenumberdisplay\par
Un autre texte.
\end{document}

Enfin... aucun problème, faut voir. Si \pagenumberdisplay est utilisé
n'importe où, il y a un risque de numéro de page erronée (problème
classique de timing). Dans un en-tête ou dans un pied de page, cela
devrait passer sans problème.

Jean-Côme Charpentier
--
<JKr> Bien sûr que non, on ne les éteint (presque) jamais, même
les Windozes.
<Jean-Côme> Je ne vois pas l'intérêt d'éteindre un truc qui s'éteint
tout seul :-)
-+- in fr.comp.text.tex -+-
mpg
2008-09-13 11:20:58 UTC
Permalink
Le (on) samedi 13 septembre 2008 01:07, Jean-Côme Charpentier a écrit
Post by Jean-Côme Charpentier
qui est un peu dommage mais c'est comme ça).
On est d'accord.
Post by Jean-Côme Charpentier
De quelle façon ?
J'aurais bien vu un
Post by Jean-Côme Charpentier
un \if donc gueule à propos d'un \fi qui ne ferme pas de \ifxxx (il
gueule aussi sur le \else). C'est normal, logique, toussa.
Euh. Osé-je te faire remarquer que le bidule est question est dans la
branche "else" de ifundefined et qu'il n'est donc censé être examiné par
TeX que si \***@frontmatter est défini, justement ?

Moi je dis que l'ECM suivant

\documentclass{minimal}

\makeatletter
\newcommand\pagenumberdisplay{%
\@ifundefined{frontmatter}{\thepage}{%
\***@frontmatter\thepage%
\else\thepage / \pageref{LastPage}%
\fi}}
\makeatother

\begin{document}
\pagenumberdisplay
\end{document}

marche chez moi et que donc GL ne nous en pas dit assez sur les
circonstances du truc (typiquement, si le \newcommand en question est
enrobé par un autre \if, ça va foirer pour la raison que Jean-Côme évoque).

Manuel.
GL
2008-09-13 15:46:57 UTC
Permalink
Post by mpg
Moi je dis que l'ECM suivant
\documentclass{minimal}
\makeatletter
\newcommand\pagenumberdisplay{%
\else\thepage / \pageref{LastPage}%
\fi}}
\makeatother
\begin{document}
\pagenumberdisplay
\end{document}
marche chez moi et que donc GL ne nous en pas dit assez sur les
circonstances du truc (typiquement, si le \newcommand en question est
enrobé par un autre \if, ça va foirer pour la raison que Jean-Côme évoque).
Manuel.
Oui autant pour moi effectivement... plates excuses, filer doux, ne pas se faire de bile...
J'avions commancé par faire tout avec des \if, et c'est là que ça merdoyait, d'où j'avais essayé un
schmoll bizarroïdal :
\ifx\iftrue\***@frontmatter
...
\fi
qui était censé tester d'un seul et même coup de TeX (Aïl!) si \***@frontmatter est défini et s'il est
\iftrue... sans succès évidemment...


Pour répondre à Jean-Côme : je définis :
\newif\***@frontmatter\@frontmatterfalse
\newif\***@backmatter\@backmatterfalse
\@ifundefined{mainmatter}{\newif\***@mainmatter\@mainmatterfalse}{}

et ensuite :
\renewcommand*\frontmatter{\clearemptydoublepage%
\@frontmattertrue \@mainmatterfalse \@backmatterfalse%
\pagenumbering{roman}}}
==> table des matières / exergue...

\renewcommand*\mainmatter{\clearemptydoublepage%
\@frontmatterfalse \@mainmattertrue \@backmatterfalse%
\pagenumbering{arabic}}}
==> bouquin

\renewcommand*\backmatter{\clearemptydoublepage%
\@frontmatterfalse \@mainmatterfalse \@backmattertrue}}
==> annexes etc.

Parce que dans \backmatter, je continue ma numérotation telle quelle, pas question de changer pour les
index, glossaires, bibliographies et autres listes de figures.

Merci mpg, je corrige mon source tt de suite !
Jose Grimm
2008-09-15 16:17:46 UTC
Permalink
Post by GL
\renewcommand*\mainmatter{\clearemptydoublepage%
\pagenumbering{arabic}}}
==> bouquin
Le premier test ne devrait-il pas concerner \***@mainmatter ?
Que se passe-t-il si \mainmatter est défini mais pas \***@mainmatter ?
et si \mainmatter est défini le \renewcommand va poser probleme.


Jose'

Jean-Côme Charpentier
2008-09-14 17:30:14 UTC
Permalink
Post by mpg
Le (on) samedi 13 septembre 2008 01:07, Jean-Côme Charpentier a écrit
Post by Jean-Côme Charpentier
qui est un peu dommage mais c'est comme ça).
On est d'accord.
Ça va.
Post by mpg
Post by Jean-Côme Charpentier
De quelle façon ?
J'aurais bien vu un
Moi aussi mais la question un peu sous jacente, c'était : vous êtes
sûr de l'avoir défini, j'ai un gros doute.
Post by mpg
Post by Jean-Côme Charpentier
un \if donc gueule à propos d'un \fi qui ne ferme pas de \ifxxx (il
gueule aussi sur le \else). C'est normal, logique, toussa.
Euh. Osé-je te faire remarquer que le bidule est question est dans la
branche "else" de ifundefined et qu'il n'est donc censé être examiné par
Tu as le droit de tout oser (avec moi) mais je ne mords pas à
l'hameçon. Reregarde le code, le \***@frontmatter est utilisé dans le
bloc \else d'un \ifundefined{frontmatter}. Or dans les classes report et
book (et sans doute d'autres) \frontmatter existe mais pas
Post by mpg
Moi je dis que l'ECM suivant
\documentclass{minimal}
\makeatletter
\newcommand\pagenumberdisplay{%
\else\thepage / \pageref{LastPage}%
\fi}}
\makeatother
\begin{document}
\pagenumberdisplay
\end{document}
marche chez moi
Il marche parce que tu es en minimal. Je n'ai même pas testé tellement
je suis sûr mais si tu mets book, ça va péter.
Post by mpg
et que donc GL ne nous en pas dit assez sur les
circonstances du truc
Là, je suis d'accord !
Post by mpg
(typiquement, si le \newcommand en question est
enrobé par un autre \if, ça va foirer pour la raison que Jean-Côme évoque).
Je pense que l'erreur fondamentale est de croire que si \frontmatter
existe alors le \***@frontmatter existera automatiquement. Il n'y a que
\***@mainmatter qui existe.

Jean-Côme Charpentier
--
"\begin{doucment} followed by \end{document}". Well, en un sens, il y
a une vérité profonde la-dessous. On commence doucement, et les
réalités du monde (et des deadlines) nous rattrapent...
-+- Jean-François in fr.comp.text.tex -+-
BriCaMatH
2008-09-06 17:39:21 UTC
Permalink
Post by mpg
Post by BriCaMatH
Manuel nous expliquera sans doute
pourquoi, je suis curieux de connaître l'explication moi aussi ;)
Ça m'ennuierait de te faire mentir, voilà donc les détails :-)
un \meaning comme toute séquence de contrôle qui se respecte (et comme
toute primitive qui se respecte, son \meaning, c'est elle-même à savoir
\ifx compare les \meaning des deux lexèmes qui le suivent, tout va pour le
mieux dans le meilleur des mondes.
c'est bien un \if dans le sens où il vaut bien \iffalse ou \iftrue), alors
Concernant l'équilibrage, c'est là que ça se gâte. En temps normal
(c'est-à-dire quand il n'est pas en train de « sauter » une branche d'un
\if), TeX s'attend à trouver autant de \fi qu'il a développé de \if.
commence par développer le \ifx, ce qui consomme les deux lexèmes suivants,
qui en particulier ne seront pas développés. Donc il li suffit d'un \fi
après pour revenir à l'équilibre.
Par contre, quand il est en train de « sauter » la branche à ignorer d'un
\if, TeX n'exécute ni ne développe quoi que ce soit. Il lit les lexèmes, et
regarde juste leur \meaning un par un. Et il compte les lexèmes qui dont le
\meaning est un \if quelconque, et vérifie qu'il sont équilibrés avec ceux
dont le \meaning est \fi. C'est là que ça se gâte : dans le deuxième
derniers \if ne sont pas avalés par le développement du précedant (pour
cause : il n'est pas développé), et TeX compte bien 3 \if, pour seulement
un \fi, et c'est le drame.
Merci pour tes explications, ça fait toujours du bien, surtout venant de
toi. C'est toujours aussi clair et agréable à lire. Au fait, j'ignorais
le truc des «\if \fi» dans branches « avalées », même si j'ai bien dû le
lire un jour dans le TeXlivre sans être assez attentif...
Sinon désolé pour ma méprise sur le \ifx\iftrue\***@openright au début de
ma réponse (peut-être trop d'éthanol dans le sang... Je devrais pas
répondre dans cet état sur des sujets aussi techniques de ça). Pourtant,
j'avais bien compris que \ifx compare les meaning des lexèmes qui
suivent, en tenant compte en plus des code de catégorie, mais j'ai pas
percuté sur l'instant. Heureusement que Manuel passe derrière moi !

Christian
--
*BriCàMatH*, des documents pour le collège

http://www.bricamath.net <http://www.bricamath.net>
Loading...