Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: How to define a macro with optional arguments in plain TeX

172 views
Skip to first unread message

Joseph Wright

unread,
Dec 19, 2007, 10:09:18 AM12/19/07
to
On Dec 19, 2:54 pm, Aditya Mahajan <adit...@umich.edu> wrote:
> On Wed, 19 Dec 2007, wensa wrote:
> > I've tried \def\foo[#1]#2{.....}
>
> > but it seems doesn't work
>
> > Who can help me on this?
>
> Basically, you need to scan the next argument and see if it is equal to [.
> If so, you execute one macro with [..] in its definition, otherwise, a
> different macro with no [...] in its definition.
>
> Suppose you have a macro \doifnextcharelse that checks the next token.
> Then something like this will work.
>
> \def\foo{\doifnextcharelse[\dofoooptional\dofoodefault}
>
> \def\dofoodefault#1{No Optional argument. Required argument: #1}
>
> \def\dofoooptional[#1]#2{Optional argument: #1. Req M7uired argument: #2}
>
> Then something like this will work.
>
> \foo{required}
>
> \foo[optional]{required}
>
> Now, plain tex does not have a macro similar to \doifnextcharelse. But
> both LaTeX and ConTeXt have one. So, the easiest thing to do it to copy
> the macro from either of these. This is how ConTeXt defines
> doifnextcharelsehttp://source.contextgarden.net/tex/context/base/syst-gen.tex?search=...)
>
> \long\def\doifnextcharelse#1#2#3% #1 should not be {} !
> {\let\charactertoken=#1% = needed here
> \def\!!stringa{#2}%
> \def\!!stringb{#3}%
> \futurelet\nexttoken\inspectnextcharacter}
>
> \def\inspectnextcharacter
> {\ifx\nexttoken\blankspace
> \@EA\reinspectnextcharacter
> \else\ifx\nexttoken\charactertoken
> \@EAEAEA\!!stringa
> \else
> \@EAEAEA\!!stringb
> \fi\fi}
>
> with
>
> \let\@EA\expandafter
> \def\@EAEAEA{\expandafter\expandafter\expandafter}
>
> LaTeX has a similar definition of doifnextcharelse . LaTeX calls it
> \@ifnextchar. Look at the definition of \@ifnextchar in latex.ltx. LaTeX's
> also provides \newcommand macro which makes it much easier to handle
> optional argument.
>
> Aditya

An example "borrowing" \@ifnextchar from latex.ltx:

\catcode`\@=11\relax
\long\def\@ifnextchar#1#2#3{%
\let\reserved@d=#1%
\def\reserved@a{#2}%
\def\reserved@b{#3}%
\futurelet\@let@token\@ifnch}
\def\@ifnch{%
\ifx\@let@token\@sptoken
\let\reserved@c\@xifnch
\else
\ifx\@let@token\reserved@d
\let\reserved@c\reserved@a
\else
\let\reserved@c\reserved@b
\fi
\fi
\reserved@c}
\def\:{\let\@sptoken= } \: % this makes \@sptoken a space token
\def\:{\@xifnch} \expandafter\def\: {\futurelet\@let@token\@ifnch}

\def\foo{%
\@ifnextchar[%]
{\foo@}
{\foo@[]}
}

\def\foo@[#1]#2{%
First argument = #1, second argument = #2}

\catcode`\@=12\relax

\foo{stuff}

\foo[more]{stuff}

\bye

Joseph Wright

wensa

unread,
Dec 19, 2007, 9:14:41 AM12/19/07
to
I've tried \def\foo[#1]#2{.....}

but it seems doesn't work

Who can help me on this?

Thanks in advance

Aditya Mahajan

unread,
Dec 19, 2007, 9:54:41 AM12/19/07
to
On Wed, 19 Dec 2007, wensa wrote:

> I've tried \def\foo[#1]#2{.....}
>
> but it seems doesn't work
>
> Who can help me on this?

Basically, you need to scan the next argument and see if it is equal to [.

If so, you execute one macro with [..] in its definition, otherwise, a
different macro with no [...] in its definition.

Suppose you have a macro \doifnextcharelse that checks the next token.
Then something like this will work.

\def\foo{\doifnextcharelse[\dofoooptional\dofoodefault}

\def\dofoodefault#1{No Optional argument. Required argument: #1}

\def\dofoooptional[#1]#2{Optional argument: #1. Req M7uired argument: #2}


Then something like this will work.

\foo{required}

\foo[optional]{required}

Now, plain tex does not have a macro similar to \doifnextcharelse. But
both LaTeX and ConTeXt have one. So, the easiest thing to do it to copy
the macro from either of these. This is how ConTeXt defines
doifnextcharelse

http://source.contextgarden.net/tex/context/base/syst-gen.tex?search=%5C%5Cdef%5C%5Cdoifnextchar)

Dan

unread,
Dec 19, 2007, 4:12:51 PM12/19/07
to
On Dec 19, 9:09 am, Joseph Wright <joseph.wri...@morningstar2.co.uk>
wrote:

> On Dec 19, 2:54 pm, Aditya Mahajan <adit...@umich.edu> wrote:
>
>
>
> > On Wed, 19 Dec 2007, wensa wrote:
> > > I've tried \def\foo[#1]#2{.....}
>
> > > but it seems doesn't work
>
> > > Who can help me on this?
>
[...]

>
>
> An example "borrowing" \@ifnextchar from latex.ltx:
[definition of \@ifnextchar snipped]

Or just \input miniltx and then \@ifnextchar is automatically
defined. Also @ is a letter and \makeatother is defined to restore
its \catcode:

\input miniltx


> \def\foo{%
> \@ifnextchar[%]
> {\foo@}
> {\foo@[]}
>
> }
>
> \def\foo@[#1]#2{%
> First argument = #1, second argument = #2}

\makeatother

> \foo{stuff}
>
> \foo[more]{stuff}
>
> \bye

miniltx also provides \@ifstar and \@for and other useful
(and some not-so-useful) commands for plain TeX.


Dan

0 new messages