mirror of
https://github.com/mirror/make.git
synced 2025-01-04 01:10:26 +08:00
* texinfo.tex: Better @macro implementation.
From: Zack Weinberg <zack@rabi.phys.columbia.edu>.
This commit is contained in:
parent
a709205e81
commit
2968844002
374
texinfo.tex
374
texinfo.tex
@ -36,10 +36,6 @@
|
|||||||
% Please include a precise test case in each bug report,
|
% Please include a precise test case in each bug report,
|
||||||
% including a complete document with which we can reproduce the problem.
|
% including a complete document with which we can reproduce the problem.
|
||||||
%
|
%
|
||||||
% Texinfo macros (with @macro) are *not* supported by texinfo.tex. You
|
|
||||||
% have to run makeinfo -E to expand macros first; the texi2dvi script
|
|
||||||
% does this.
|
|
||||||
%
|
|
||||||
% To process a Texinfo manual with TeX, it's most reliable to use the
|
% To process a Texinfo manual with TeX, it's most reliable to use the
|
||||||
% texi2dvi shell script that comes with the distribution. For simple
|
% texi2dvi shell script that comes with the distribution. For simple
|
||||||
% manuals, you can get away with:
|
% manuals, you can get away with:
|
||||||
@ -791,13 +787,6 @@ where each line of input produces a line of output.}
|
|||||||
\def\menu{\doignore{menu}}
|
\def\menu{\doignore{menu}}
|
||||||
\def\direntry{\doignore{direntry}}
|
\def\direntry{\doignore{direntry}}
|
||||||
|
|
||||||
% Also ignore @macro ... @end macro. The user must run texi2dvi,
|
|
||||||
% which runs makeinfo to do macro expansion. Ignore @unmacro, too.
|
|
||||||
\def\macro{\doignore{macro}}
|
|
||||||
\def\macrocsname{macro}
|
|
||||||
\let\unmacro = \comment
|
|
||||||
|
|
||||||
|
|
||||||
% @dircategory CATEGORY -- specify a category of the dir file
|
% @dircategory CATEGORY -- specify a category of the dir file
|
||||||
% which this file should belong to. Ignore this in TeX.
|
% which this file should belong to. Ignore this in TeX.
|
||||||
\let\dircategory = \comment
|
\let\dircategory = \comment
|
||||||
@ -828,13 +817,7 @@ where each line of input produces a line of output.}
|
|||||||
% @c @end ifinfo
|
% @c @end ifinfo
|
||||||
% and the @end ifinfo will be properly ignored.
|
% and the @end ifinfo will be properly ignored.
|
||||||
% (We've just changed @ to catcode 12.)
|
% (We've just changed @ to catcode 12.)
|
||||||
%
|
\catcode`\c = 14
|
||||||
% But we can't do this if #1 is `macro', since that actually contains a c.
|
|
||||||
% Happily, none of the other conditionals have the letter `c' in their names!
|
|
||||||
\def\temp{#1}%
|
|
||||||
\ifx\temp\macrocsname \else
|
|
||||||
\catcode`\c = 14
|
|
||||||
\fi
|
|
||||||
%
|
%
|
||||||
% And now expand that command.
|
% And now expand that command.
|
||||||
\doignoretext
|
\doignoretext
|
||||||
@ -1123,22 +1106,6 @@ where each line of input produces a line of output.}
|
|||||||
% @bye.
|
% @bye.
|
||||||
\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
|
\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
|
||||||
|
|
||||||
% \def\macro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\macroxxx}
|
|
||||||
% \def\macroxxx#1#2 \end macro{%
|
|
||||||
% \expandafter\gdef\macrotemp#1{#2}%
|
|
||||||
% \endgroup}
|
|
||||||
|
|
||||||
%\def\linemacro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\linemacroxxx}
|
|
||||||
%\def\linemacroxxx#1#2 \end linemacro{%
|
|
||||||
%\let\parsearg=\relax
|
|
||||||
%\edef\macrotempx{\csname M\butfirst\expandafter\string\macrotemp\endcsname}%
|
|
||||||
%\expandafter\xdef\macrotemp{\parsearg\macrotempx}%
|
|
||||||
%\expandafter\gdef\macrotempx#1{#2}%
|
|
||||||
%\endgroup}
|
|
||||||
|
|
||||||
%\def\butfirst#1{}
|
|
||||||
|
|
||||||
|
|
||||||
\message{fonts,}
|
\message{fonts,}
|
||||||
|
|
||||||
% Font-change commands.
|
% Font-change commands.
|
||||||
@ -4385,91 +4352,196 @@ width0pt\relax} \fi
|
|||||||
|
|
||||||
\message{macros,}
|
\message{macros,}
|
||||||
% @macro.
|
% @macro.
|
||||||
% The basic scheme is as follows:
|
|
||||||
% We read the first line and split it up into macro name and parameter
|
|
||||||
% list. We then walk the parameter list defining control sequences
|
|
||||||
% named \MAC@<macro name><parameter name>. Each expands to another
|
|
||||||
% control sequence named \MAC@<macro name>.<parameter number>. Those
|
|
||||||
% control sequences will be defined at macro runtime to be the
|
|
||||||
% parameter expansion text.
|
|
||||||
%
|
|
||||||
% The body is then read in as a single argument in a context where \
|
|
||||||
% is an active character, and the cs \MACb.<macro name> is defined as
|
|
||||||
% the macro body. The active character \ takes one argument delimited
|
|
||||||
% by another \, and uses it to index the table of macro arguments
|
|
||||||
% described above.
|
|
||||||
%
|
|
||||||
% Finally, we define a control sequence \<macro name> which calls one
|
|
||||||
% of the six (!) macro execution commands. These six commands
|
|
||||||
% correspond to recursive and nonrecursive macros with no, one, and
|
|
||||||
% many arguments. They all take one argument, <macro name>, set up
|
|
||||||
% the environment appropriately, and call the real macro.
|
|
||||||
%
|
|
||||||
% \macsave@<macro name> holds the old definition of \<macro name>.
|
|
||||||
|
|
||||||
\newcount\paramno
|
% To do this right we need a feature of e-TeX, \scantokens,
|
||||||
\newtoks\macname
|
% which we arrange to emulate with a temporary file in ordinary TeX.
|
||||||
|
\ifx\eTeXversion\undefined
|
||||||
|
\newwrite\macscribble
|
||||||
|
\def\scantokens#1{%
|
||||||
|
% \toks0={#1}%
|
||||||
|
\immediate\openout\macscribble=\jobname.tmp
|
||||||
|
\immediate\write\macscribble{#1}%\the\toks0}%
|
||||||
|
\immediate\closeout\macscribble
|
||||||
|
\input \jobname.tmp
|
||||||
|
}
|
||||||
|
\fi
|
||||||
|
|
||||||
% This does \let #1 = #2, except with \csnames.
|
\newcount\paramno % Count of parameters
|
||||||
|
\newtoks\macname % Macro name
|
||||||
|
\newif\ifrecursive % Is it recursive?
|
||||||
|
|
||||||
|
% Utility: does \let #1 = #2, except with \csnames.
|
||||||
\def\cslet#1#2{%
|
\def\cslet#1#2{%
|
||||||
\expandafter\expandafter\expandafter
|
\expandafter\expandafter
|
||||||
\let
|
\expandafter\let
|
||||||
\expandafter\expandafter
|
\expandafter\expandafter
|
||||||
\csname#1\endcsname
|
\csname#1\endcsname
|
||||||
\csname#2\endcsname}
|
\csname#2\endcsname}
|
||||||
|
|
||||||
% We have to play lots of games with the catcodes. Initially { and }
|
% Macro bodies are absorbed as an argument in a context where
|
||||||
% are made `other' so that \splitarg (below) can use them as argument
|
% all characters are catcode 10, 11 or 12, except \ which is active
|
||||||
% delimiters. Then - is made a letter so that \iimacro can recognize
|
% (as in normal texinfo). It is necessary to change the definition of \.
|
||||||
% @allow-recursion.
|
|
||||||
\def\macro{\bgroup\catcode`\{=\other\catcode`\}=\other\parsearg\imacro}
|
\def\macrobodyctxt{%
|
||||||
\def\imacro#1{\egroup % started in \macro
|
\catcode`\~=12
|
||||||
\splitarg{#1}% now \macname is the macname and \toks0 the arglist
|
\catcode`\^=12
|
||||||
\paramno=0%
|
\catcode`\_=12
|
||||||
\edef\tmp{\the\toks0}%
|
\catcode`\|=12
|
||||||
\ifx\tmp\empty % no arguments
|
\catcode`\<=12
|
||||||
|
\catcode`\>=12
|
||||||
|
\catcode`\+=12
|
||||||
|
\catcode`\{=12
|
||||||
|
\catcode`\}=12
|
||||||
|
\catcode`\@=12
|
||||||
|
\catcode`\^^M=10
|
||||||
|
\usembodybackslash}
|
||||||
|
|
||||||
|
% \mbodybackslash is the definition of \ in @macro bodies.
|
||||||
|
% It maps \foo\ => \csname macarg.foo\endcsname => #N
|
||||||
|
% where N is the macro parameter number.
|
||||||
|
% We define \csname macarg.\endcsname to be \realbackslash, so
|
||||||
|
% \\ in macro replacement text gets you a backslash.
|
||||||
|
|
||||||
|
{\catcode`@=0 \catcode`\\=\active
|
||||||
|
@gdef@usembodybackslash{@let\=@mbodybackslash}
|
||||||
|
@gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
|
||||||
|
}
|
||||||
|
\expandafter\def\csname macarg.\endcsname{\realbackslash}
|
||||||
|
|
||||||
|
% The catcode games are necessary because @macro may or may not
|
||||||
|
% have a brace-surrounded list of arguments, and we need to do
|
||||||
|
% different stuff in each case. Making {, } \other is the only
|
||||||
|
% way to prevent their being deleted by the tokenizer.
|
||||||
|
\def\macro{\recursivefalse
|
||||||
|
\bgroup\catcode`\{=\other\catcode`\}=\other\parsearg\macroxxx}
|
||||||
|
\def\rmacro{\recursivetrue
|
||||||
|
\bgroup\catcode`\{=\other\catcode`\}=\other\parsearg\macroxxx}
|
||||||
|
|
||||||
|
\def\macroxxx#1{\egroup % started in \macro
|
||||||
|
\getargs{#1}% now \macname is the macname and \toks0 the arglist
|
||||||
|
\edef\temp{\the\toks0}%
|
||||||
|
\ifx\temp\empty % no arguments
|
||||||
|
\paramno=0%
|
||||||
\else
|
\else
|
||||||
\expandafter\parsemargdef \the\toks0;%
|
\expandafter\parsemargdef \the\toks0;%
|
||||||
\fi
|
\fi
|
||||||
\bgroup\catcode`\-=11\global\futurelet\nxt\iimacro}
|
\expandafter\ifx \csname macsave.\the\macname\endcsname \relax
|
||||||
|
\cslet{macsave.\the\macname}{\the\macname}%
|
||||||
% \imacro has noted whether the macro takes one, two, or many
|
|
||||||
% arguments (in \paramno). \iimacro figures out whether it's
|
|
||||||
% recursive, and then uses the argument count and the recursivity to
|
|
||||||
% select one of the six macro execution sequences. Then we save the
|
|
||||||
% original definition of @foo in \macsave@foo, and define @foo to call
|
|
||||||
% the selected execution sequence. \edef conveniently just expands
|
|
||||||
% the token registers, not the deep structure.
|
|
||||||
\def\iimacro{%
|
|
||||||
\egroup % started in \imacro
|
|
||||||
\ifx\nxt\allowrecur
|
|
||||||
\let\next\parserbody
|
|
||||||
\toks0=\expandafter{\csname dormacro\ifcase\paramno na\or oa\fi\endcsname}%
|
|
||||||
\else
|
\else
|
||||||
\let\next\parsebody
|
\message{Warning: redefining \the\macname}%
|
||||||
\toks0=\expandafter{\csname domacro\ifcase\paramno na\or oa\fi\endcsname}%
|
|
||||||
\fi
|
\fi
|
||||||
\expandafter\ifx \csname macsave@\the\macname\endcsname \relax
|
\begingroup \macrobodyctxt
|
||||||
\cslet{macsave@\the\macname}{\the\macname}%
|
\ifrecursive \expandafter\parsermacbody
|
||||||
|
\else \expandafter\parsemacbody
|
||||||
|
\fi}
|
||||||
|
|
||||||
|
\def\unmacro{\parsearg\unmacroxxx}
|
||||||
|
\def\unmacroxxx#1{
|
||||||
|
\expandafter\ifx \csname macsave.\the\macname\endcsname \relax
|
||||||
|
\errmessage{Macro \the\macname\ not defined.}%
|
||||||
\else
|
\else
|
||||||
\errmessage{warning: redefining macro \the\macname}%
|
\cslet{#1}{macsave.#1}%
|
||||||
|
\expandafter\let \csname macsave.\the\macname\endcsname \undefined
|
||||||
\fi
|
\fi
|
||||||
\expandafter\edef\csname\the\macname\endcsname{\the\toks0{\the\macname}}%
|
}
|
||||||
\next}
|
|
||||||
|
|
||||||
% @allow-recursion is noticed and handled by \iimacro. It should
|
% Parse the optional {params} list. Set up \paramno and \paramlist
|
||||||
% never actually be executed. It has two names so we don't need
|
% so \defmacro knows what to do. Define \macarg.blah for each blah
|
||||||
% strange catcodes while defining \iimacro.
|
% in the params list, to be ##N where N is the position in that list.
|
||||||
\def\allowrecur{\errmessage{Internal error: \noexpand\allowrecur executed}}
|
% That gets used by \mbodybackslash (above).
|
||||||
{\catcode`\-=11\global\let\allow-recursion\allowrecur}
|
|
||||||
|
|
||||||
% unmacro just restores the old meaning; the MAC@<macname> macros
|
% This code has to take great care with `macro parameter char #'. The
|
||||||
% remain defined. (Memory leak!) \norecurse is defined below, near
|
% eight hashes in a row on the macarg.#1 line collapse to four in the
|
||||||
% the execution commands.
|
% definition of \macarg.blah, to two when \parsemacbody expands the
|
||||||
\def\unmacro{\parsearg\iunmacro}
|
% macro replacement text, and to one when \defmacro writes the macro
|
||||||
\def\iunmacro#1{\macname={#1} \norecurse}
|
% definiton. The games with \twohash are to postpone expansion till
|
||||||
|
% the very end, when \parsemargdefyyy crunches \paramlist into
|
||||||
|
% something that can be splatted into a \expandafter\def\blah line (in
|
||||||
|
% \defmacro).
|
||||||
|
\def\parsemargdef#1;{\paramno=0\def\paramlist{}\parsemargdefxxx#1,;,}
|
||||||
|
\def\parsemargdefxxx#1,{%
|
||||||
|
\let\twohash\relax
|
||||||
|
\if#1;\let\next=\parsemargdefyyy
|
||||||
|
\else \let\next=\parsemargdefxxx
|
||||||
|
\advance\paramno by 1%
|
||||||
|
\expandafter\edef\csname macarg.#1\endcsname{########\the\paramno}%
|
||||||
|
\edef\paramlist{\paramlist\twohash\twohash\the\paramno,}%
|
||||||
|
\fi\next}
|
||||||
|
\def\parsemargdefyyy{\let\twohash##\relax \edef\paramlist{\paramlist}}
|
||||||
|
|
||||||
% We need {} to be ordinary inside these commands. [] are temporary
|
% These two commands read recursive and nonrecursive macro bodies.
|
||||||
|
% (They're different since rec and nonrec macros end differently.)
|
||||||
|
|
||||||
|
\long\def\parsemacbody#1@end macro%
|
||||||
|
{\xdef\temp{#1} \endgroup\defmacro}%
|
||||||
|
\long\def\parsermacbody#1@end macro%
|
||||||
|
{\xdef\temp{#1} \endgroup\defmacro}%
|
||||||
|
|
||||||
|
|
||||||
|
% This defines the macro itself. There are six cases: recursive and
|
||||||
|
% nonrecursive macros of zero, one, and many arguments.
|
||||||
|
% Much magic with \expandafter here.
|
||||||
|
\def\defmacro{%
|
||||||
|
\ifrecursive
|
||||||
|
\ifcase\paramno
|
||||||
|
% 0
|
||||||
|
\expandafter\edef\csname\the\macname\endcsname{%
|
||||||
|
\noexpand\scantokens{\temp}}%
|
||||||
|
\or % 1
|
||||||
|
\expandafter\edef\csname\the\macname\endcsname{%
|
||||||
|
\noexpand\braceorline\csname\the\macname xxx\endcsname}%
|
||||||
|
\expandafter\edef\csname\the\macname xxx\endcsname##1{%
|
||||||
|
\noexpand\scantokens{\temp}}%
|
||||||
|
\else % many
|
||||||
|
\expandafter\edef\csname\the\macname\endcsname##1{%
|
||||||
|
\csname\the\macname xxx\endcsname ##1,}%
|
||||||
|
\expandafter\expandafter
|
||||||
|
\expandafter\edef
|
||||||
|
\expandafter\expandafter
|
||||||
|
\csname\the\macname xxx\endcsname
|
||||||
|
\paramlist{\noexpand\scantokens{\temp}}%
|
||||||
|
\fi
|
||||||
|
\else
|
||||||
|
\ifcase\paramno
|
||||||
|
% 0
|
||||||
|
\expandafter\edef\csname\the\macname\endcsname{%
|
||||||
|
\noexpand\norecurse{\the\macname}%
|
||||||
|
\noexpand\scantokens{\temp}\egroup}%
|
||||||
|
\or % 1
|
||||||
|
\expandafter\edef\csname\the\macname\endcsname{%
|
||||||
|
\noexpand\braceorline\csname\the\macname xxx\endcsname}%
|
||||||
|
\expandafter\edef\csname\the\macname xxx\endcsname##1{%
|
||||||
|
\noexpand\norecurse{\the\macname}
|
||||||
|
\noexpand\scantokens{\temp}\egroup}%
|
||||||
|
\else % many
|
||||||
|
\expandafter\edef\csname\the\macname\endcsname##1{%
|
||||||
|
\csname\the\macname xxx\endcsname ##1,}%
|
||||||
|
\expandafter\expandafter
|
||||||
|
\expandafter\edef
|
||||||
|
\expandafter\expandafter
|
||||||
|
\csname\the\macname xxx\endcsname
|
||||||
|
\paramlist{%
|
||||||
|
\noexpand\norecurse{\the\macname}
|
||||||
|
\noexpand\scantokens{\temp}\egroup}%
|
||||||
|
\fi
|
||||||
|
\fi}
|
||||||
|
|
||||||
|
\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
|
||||||
|
|
||||||
|
% \braceorline decides whether the next nonwhitespace character is a
|
||||||
|
% {. If so it reads up to the closing }, if not, it reads the whole
|
||||||
|
% line. Whatever was read is then fed to the next control sequence
|
||||||
|
% as an argument (by \parsebrace or \parsearg)
|
||||||
|
\def\braceorline{\bgroup
|
||||||
|
\catcode`\{=\other\catcode`\}=\other \futurelet\nxt\braceorlinexxx}
|
||||||
|
\def\braceorlinexxx{%
|
||||||
|
\ifx\nxt\brace
|
||||||
|
\expandafter\parsebrace
|
||||||
|
\else
|
||||||
|
\egroup \expandafter\parsearg
|
||||||
|
\fi}
|
||||||
|
|
||||||
|
% We need {} to be \other inside these commands. [] are temporary
|
||||||
% grouping symbols.
|
% grouping symbols.
|
||||||
\begingroup
|
\begingroup
|
||||||
\catcode`\{=\other \catcode`\}=\other
|
\catcode`\{=\other \catcode`\}=\other
|
||||||
@ -4477,110 +4549,30 @@ width0pt\relax} \fi
|
|||||||
|
|
||||||
% @macro can be called with or without a brace-surrounded macro
|
% @macro can be called with or without a brace-surrounded macro
|
||||||
% argument list. These three sequences extract the macro name and arg
|
% argument list. These three sequences extract the macro name and arg
|
||||||
% list in hopefully all cases. *Note, anything on the line after the
|
% list in hopefully all cases. Note that anything on the line after the
|
||||||
% first pair of braces will be thrown out.
|
% first pair of braces will be thrown out (Makeinfo puts it into the
|
||||||
\gdef\splitarg#1[\isplitarg|#1 {}|]
|
% macro body).
|
||||||
\gdef\isplitarg|#1 {#2}#3|[%
|
\gdef\getargs#1[\getargsxxx|#1 {}|]
|
||||||
|
\gdef\getargsxxx|#1 {#2}#3|[%
|
||||||
\toks0=[#2]%
|
\toks0=[#2]%
|
||||||
\edef\tmp[\the\toks0]%
|
\edef\tmp[\the\toks0]%
|
||||||
\ifx\tmp\empty
|
\ifx\tmp\empty
|
||||||
\isplitargnospaces|#1{}|%
|
\getargsnospaces|#1{}|%
|
||||||
\else
|
\else
|
||||||
\macname=[#1]%
|
\macname=[#1]%
|
||||||
\fi]
|
\fi]
|
||||||
\gdef\isplitargnospaces|#1{#2}#3|[\macname=[#1] \toks0=[#2]]
|
\gdef\getargsnospaces|#1{#2}#3|[\macname=[#1]\toks0=[#2]]
|
||||||
|
|
||||||
% \parsebrace gets around the situation produced by \braceorline
|
% \parsebrace gets around the situation produced by \braceorline
|
||||||
% (below) where the { has the wrong catcode because of \futurelet.
|
% (above) where the { has the wrong catcode because of \futurelet.
|
||||||
% The \egroup matches a \bgroup in \braceorline.
|
% The \egroup matches a \bgroup in \braceorline.
|
||||||
\gdef\parsebrace#1{#2}[\egroup\let\next=#1\next[#2]]
|
\gdef\parsebrace#1{#2}[\egroup\let\next=#1\next[#2]]
|
||||||
|
|
||||||
\global\let\brace={ % used by \braceorline, below
|
\global\let\brace={ % used by \braceorline
|
||||||
|
|
||||||
\endgroup
|
\endgroup
|
||||||
|
|
||||||
|
|
||||||
% Argument parsing.
|
|
||||||
% These routines iterate over a comma-separated list defining
|
|
||||||
% tokens that map macro formal to actual parameters.
|
|
||||||
% \parsemargdef sets the formal -> positional correspondence at macro
|
|
||||||
% definition time; \parsemarg sets positional -> actual at runtime.
|
|
||||||
%
|
|
||||||
% The definitions are not symmetric because the callers have the
|
|
||||||
% argument list in different places (token register and #arg)
|
|
||||||
\def\parsemargdef#1;{\paramno=0\iparsemargdef#1,;,}
|
|
||||||
\def\iparsemargdef#1,{%
|
|
||||||
\if#1;\let\next=\relax
|
|
||||||
\else \let\next=\iparsemargdef
|
|
||||||
\advance\paramno by 1%
|
|
||||||
\expandafter\edef\csname MAC@\the\macname#1\endcsname
|
|
||||||
{\csname MAC@\the\macname.\the\paramno\endcsname}%
|
|
||||||
\fi\next}
|
|
||||||
|
|
||||||
\def\parsemarg#1{\paramno=1\iparsemarg#1,;,}
|
|
||||||
\def\iparsemarg#1,{%
|
|
||||||
\if#1;\let\next=\relax
|
|
||||||
\else \let\next=\iparsemarg
|
|
||||||
\expandafter\def\csname MAC@\the\macname.\the\paramno\endcsname{#1}%
|
|
||||||
\advance\paramno by 1%
|
|
||||||
\fi\next}
|
|
||||||
|
|
||||||
% Argument substitution.
|
|
||||||
% \ is active when the body is read and tokenized; it converts its
|
|
||||||
% argument to a macro-argument name and expands it. We use | as a
|
|
||||||
% temporary escape character.
|
|
||||||
{
|
|
||||||
\catcode`\|=0 |catcode`|\=|active
|
|
||||||
|gdef\#1\{|csname MAC@|the|macname#1|endcsname}
|
|
||||||
}
|
|
||||||
|
|
||||||
% These sequences read and save the macro body. \parserbody absorbs
|
|
||||||
% the @allow-recursion in its argument, and then falls through to
|
|
||||||
% \parsebody.
|
|
||||||
\def\parsebody{\begingroup\catcode`\\=\active\iparsebody}
|
|
||||||
\def\parserbody#1{\parsebody}
|
|
||||||
|
|
||||||
% \iparsebody reads the entire macro in as an argument. \ was made
|
|
||||||
% active by \parsebody while the reading occurs.
|
|
||||||
\long\def\iparsebody#1 \end macro% The space eats the final CR.
|
|
||||||
{\endgroup % started in \parsebody
|
|
||||||
\expandafter\def\csname MACb.\the\macname \endcsname{#1}}
|
|
||||||
|
|
||||||
% These six sequences execute recursive and nonrecursive macros of no,
|
|
||||||
% one, and many arguments. We need to distinguish one arg from many
|
|
||||||
% args because a one-argument macro invoked with no arguments gets the
|
|
||||||
% rest of the line as its argument.
|
|
||||||
%
|
|
||||||
% Please note that all macros are executed inside a group, so any
|
|
||||||
% changes made by a macro (@set, etc.) won't stick.
|
|
||||||
\def\dormacrona#1{\begingroup\macname={#1}\idomacro{}}
|
|
||||||
\def\dormacrooa#1{\begingroup\macname={#1}\braceorline}
|
|
||||||
\def\dormacro#1{\begingroup\macname={#1}\idomacro}
|
|
||||||
|
|
||||||
\def\domacrona#1{\begingroup\macname={#1}\norecurse\idomacro{}}
|
|
||||||
\def\domacrooa#1{\begingroup\macname={#1}\norecurse\braceorline}
|
|
||||||
\def\domacro#1{\begingroup\macname={#1}\norecurse\idomacro}
|
|
||||||
|
|
||||||
% some helpers:
|
|
||||||
\def\norecurse{\cslet{\the\macname}{macsave@\the\macname}}
|
|
||||||
\def\idomacro#1{\parsemarg{#1}\csname MACb.\the\macname\endcsname\endgroup}
|
|
||||||
|
|
||||||
% \braceorline decides whether the next nonwhitespace character is a
|
|
||||||
% {. If so it reads up to the closing }, if not, it reads the whole
|
|
||||||
% line. Whatever was read is then fed to \idomacro. \parsebrace is
|
|
||||||
% defined above, near \splitarg, in a strange catcode environment;
|
|
||||||
% this is necessary because \futurelet freezes the catcode of the
|
|
||||||
% peeked-at character.
|
|
||||||
\def\braceorline{\bgroup
|
|
||||||
\catcode`\{=\other\catcode`\}=\other \futurelet\nxt\ibraceorline}
|
|
||||||
\def\ibraceorline{%
|
|
||||||
\ifx\nxt\brace
|
|
||||||
\expandafter\parsebrace
|
|
||||||
\else
|
|
||||||
\egroup \expandafter\parsearg
|
|
||||||
\fi \idomacro}
|
|
||||||
|
|
||||||
|
|
||||||
\message{cross references,}
|
\message{cross references,}
|
||||||
\newwrite\auxfile
|
\newwrite\auxfile
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user