这份简短的文件:
\documentclass[a4paper]{report}
\usepackage{gnu}
\begin{document}
\end{document}
使用以下软件包:
%!TEX encoding = UTF-8 Unicode
\def\fileversion{2.7}
\def\filedate{%
Tue 2014-07-22
}
\NeedsTeXFormat{LaTeX2e}[1996/06/01]
\typeout{Package 'mworx' (\filedate).}
\ProvidesPackage{gnu}
\RequirePackage{kvoptions}
\SetupKeyvalOptions{family=mworx,prefix=mw@,setkeys=\setkeys}
\newif\if@read\@readfalse
\newif\if@grave\@gravefalse
\DeclareBoolOption[true]{greek}
\DeclareVoidOption{ifgrave}{\@gravetrue}
\DeclareVoidOption{read}{\@readtrue}
\DeclareBoolOption[true]{save}
\DeclareBoolOption[false]{inpenc}
\DeclareBoolOption[false]{pack}
\DeclareBoolOption[true]{rootsyst}
\DeclareBoolOption[true]{loop}
\DeclareBoolOption[true]{fnsect}
\DeclareBoolOption[false]{fonts}
\DeclareBoolOption[false]{ptmx}
\DeclareBoolOption[true]{bb}
\DeclareBoolOption[true]{misc}
\DeclareBoolOption[true]{lengths}
\DeclareBoolOption[true]{dps}
\DeclareBoolOption[true]{xtras}
\DeclareBoolOption[true]{thm}
\DeclareBoolOption[true]{block}
\DeclareBoolOption[true]{mathdel}
\DeclareBoolOption[true]{mwmath}
\DeclareBoolOption[true]{oper}
\DeclareBoolOption[true]{mathsymb}
\ProcessKeyvalOptions*\relax
%Option "fonts"
\ifmw@fonts
\RequirePackage{ifxetex,ifluatex}
\newif\ifengineright\enginerightfalse%Define new if to check if luatex or xetex are being used. To avoid typing the xetex/luatex commands twice.
\ifengineright %Add those commands
\setmathrm{Times New Roman}
\setmathsf{Times New Roman}
\setmathtt{Times New Roman}
\setboldmathrm[BoldFont={Optima ExtraBlack}]{Optima Bold}
\defaultfontfeatures{Mapping=tex-text}
\setromanfont{Times New Roman}
\setsansfont{Times New Roman}
\setmonofont{Helvetica}
\newfontfamily{\vrb}{Helvetica}
\newfontfamily{\Ak}{Akkadian}%
\newfontfamily{\mapu}{Arial Unicode MS}
\newfontfamily{\Ar}{Geeza Pro}
\newfontfamily{\Chs}{STSong}
\newfontfamily{\Cht}{PMingLiU}
\newfontfamily{\Ja}{MS Mincho}
\newfontfamily{\Ru}{Times New Roman}
\newfontfamily{\Gr}{Times New Roman}
\newfontfamily{\He}{Times New Roman}
\newfontfamily{\Ko}{Batang}
\newfontfamily{\Ind}{Devanagari MT}
\newfontfamily{\Mal}{Malayalam MN}
\newfontfamily{\Sinh}{Free Sans}
\newfontfamily{\Thai}{Free Serif}
\newcommand{\€}{\Gr{ }}
\else
{}
\fi
%More commands that are OK in any engine I know of.
\newcommand{\mbold}{\mathbf}
\newcommand{\tbold}{\textbf}
\newcommand{\ital}{\textit}
\newcommand{\CAPS}{\textsc}
\newcommand{\slant}{\textsl}
\newcommand{\bemph}[1]{\tbold{\emph{#1}}}
\newcommand{\mrm}{\mathrm}
\fi
%Option "misc"
\ifmw@misc
%A few unclassifiable shortcuts.
\RequirePackage{color,graphicx,xparse}
\newcommand{\tick}{\checkmark}
\newcommand{\crux}{\dagger}
\newcommand{\dcrux}{\ddagger}
\newcommand{\hs}{\heartsuit}
\newcommand{\ds}{\diamondsuit}
\newcommand{\cs}{\clubsuit}
\renewcommand{\ss}{\spadesuit}
\newcommand{\tcrux}{$\dagger$}
\newcommand{\tdcrux}{$\ddagger$}
\newcommand{\ths}{$\heartsuit$}
\newcommand{\tds}{$\diamondsuit$}
\newcommand{\tcs}{$\clubsuit$}
\newcommand{\tss}{$\spadesuit$}
\newcommand{\bs}{\backslash}
\newcommand{\tbs}{$\bs$}
\newcommand{\bk}{\Gr{ }}
\NewDocumentCommand{O{1}O{1}}
{\scalebox{#1}[#2]{\color{white}a}}
\fi
\endinput
在第 83 行生成错误Extra \fi
(紧接着\newcommand{\mrm}{\mathrm}
。如果我添加:
\ifxetex
\enginerighttrue
\else
\ifluatex
\enginerighttrue
\else
{}
\fi
\fi
之前\ifengineright
,错误变为Undefined control sequence. l.56 \ifengineright
。
这里发生了什么事?
答案1
问题出在哪里?下面我们来分析一下。
你有
\ifmw@fonts
\RequirePackage{ifxetex,ifluatex}
\newif\ifengineright\enginerightfalse%Define new if to check if luatex or xetex are being used. To avoid typing the xetex/luatex commands twice.
\ifengineright %Add those commands
\setmathrm{Times New Roman}
\setmathsf{Times New Roman}
% several other lines
\else
{}
\fi
%More commands that are OK in any engine I know of.
\newcommand{\mbold}{\mathbf}
\newcommand{\tbold}{\textbf}
\newcommand{\ital}{\textit}
\newcommand{\CAPS}{\textsc}
\newcommand{\slant}{\textsl}
\newcommand{\bemph}[1]{\tbold{\emph{#1}}}
\newcommand{\mrm}{\mathrm}
\fi
当\ifmw@fonts
返回 false 时,“真实代码”不会被执行,因此\ifengineright
没有定义,也不被视为条件。因此第一的 \else
被认为是 的“真代码”的结束\ifmw@fonts
,而“假代码”只包含{}
。
如果\ifmw@fonts
返回 true,TeX 定义\ifengineright
. 并且一切都会顺利进行。
让我们看一个简化的例子:
\newif\ifOUTER % \OUTERfalse is implicit
%\OUTERtrue
\ifOUTER
\newif\ifINNER % \INNERfalse is implicit
\ifINNER
\message{We're here}
\else
{}
\fi
\else
\message{Outer}
\fi
错误信息是
! Extra \else.
l.12 \else
?
Outer
! Extra \fi.
l.14 \fi
?
当\OUTERtrue
取消注释时,我们不会收到任何错误。
所发生的情况很容易解释:当一个条件为真时,TeX 会简单地删除它以及用于确定布尔值的标记,然后只\else
删除“错误文本”。
但当条件返回 false 时全部匹配的标记\else
(或\fi
,如果没有\else
后续标记)将被删除,并且不会以任何方式进行解释,除非其中的条件与其对应的 匹配\fi
。但是,\ifengineright
在您的代码中, 不是条件,而只是未定义的标记。
TeX 如何确定标记是否为条件?当然,任何原始条件都会被识别,此外,\let
原始条件的所有标记也是如此。事实上,\enginerighttrue
和分别\enginerightfalse
执行\let\ifengineright\iftrue
和\let\ifengineright\iffalse
。其他都不是条件。或的标记\let
以类似的方式被识别为结束(分支)条件。\else
\fi
道理就是“永远不要在条件语句中定义新的条件语句”。好吧,这是可以做到的,但不能用这种方式。
顺便说一句,\else {} \fi
空的假文本不是好的编程:条件是完全可扩展的构造,除非需要,否则不要添加不可扩展的标记。
答案2
不要这样做:
\ifmw@fonts
\RequirePackage{ifxetex,ifluatex}
\newif\ifengineright
如果您在条件部分中分配一个新的 if,则\ifengineright
可能会或可能不会定义,但\fi
始终是 fi,因此在未定义的情况下您会有不匹配的 fi。