
Рассмотрим такой пример:
\documentclass{report}
\def\startnewpart{FALSE}
\makeatletter
\renewcommand\chapter{\if@openright\cleardoublepage\else\clearpage\fi
% \def\startnewpart{FALSE}
\thispagestyle{plain}%
\global\@topnum\z@
\@afterindentfalse
\secdef\@chapter\@schapter
% \def\startnewpart{FALSE}
}
\makeatother
\begin{document}
\tableofcontents
\chapter{Methods}
Some text
\end{document}
Если \renewcommand\chapter
я раскомментирую первый, \def\startnewpart{FALSE}
документ скомпилируется нормально.
Если вместо этого я раскомментирую второй, то \def\startnewpart{FALSE}
получу ошибку:
Chapter 1.
! Missing { inserted.
\@makechapterhead ...1\par \nobreak \vskip 40\p@ }
l.21 \tableofcontents
В чем разница?
В этом примере я изучаю, как использовать управляющую переменную \startnewpart
для управления выполнением \chapter
. \def\startnewpart{FALSE}
Она предназначена для сброса значения \startnewpart
.
решение1
\secdef
определяется как
% latex.ltx, line 6086:
\def\secdef#1#2{\@ifstar{#2}{\@dblarg{#1}}}
В вашем случае вы получаете
\@ifstar{\@schapter}{\@dblarg{\@chapter}}
Теперь \@ifstar
смотрим на следующий токен. Если раскомментировать вторую \def
строку, то следующим токеном будет не *
, а \def
. Таким образом, LaTeX находит
\@dblarg{\@chapter}\def\startnewpart{FALSE}
Вот определение \@dblarg
:
% latex.ltx, line 1105:
\long\def\@dblarg#1{\kernel@ifnextchar[{#1}{\@xdblarg{#1}}}
Таким образом вы получаете
\kernel@ifnextchar[{\@chapter}{\@xdblarg{\@chapter}}\def\startnewpart{FALSE}
Макрос \kernel@ifnextchar
поглощает три аргумента, здесь [
, {\@chapter}
и {\@xdblarg{\@chapter}}
и проверяет, является ли следующий токен [
. Это не так, потому что это \def
, поэтому эффект заключается в том, чтобы получить
\@xdblarg{\@chapter}\def\startnewpart{FALSE}
Хорошо, давайте посмотрим \@xdblarg
:
% latex.ltx, line 1106:
\long\def\@xdblarg#1#2{#1[{#2}]{#2}}
Вот (но по правилам скобки будут удалены), так что в итоге у вас #1
получится{\@chapter}
\@chapter[{\def}]{\def}\startnewpart{FALSE}
что, безусловно, не то, что вы хотели бы иметь в своем коде.
На самом деле это не связано с \def
. Такие команды, как
\secdef\A\B
\@ifstar{A}{B}
\@ifnextchar<char>{A}{B}
долженвсегдаидут последними в коде определения, потому что хотят увидеть, что будет дальше.