TeX - LaTeX Asked by Miquel Ortega on April 15, 2021
While writing a test for l3build I ran across a problem on outputting the result of a command that used @ifnextchar
. Concretely, TYPE{command}
gave a compiling error. I have reduced it to the following MWE:
documentclass{article}
begin{document}
makeatletter
DeclareRobustCommandlookahead{@ifnextchar{z}{hello}{goodbye}}
immediatewrite128{lookahead z}
makeatother
end{document}
On my machine (pdflatex, TeX Live 2020/Debian) the previous code gives the error: Argument of reserved@a has an extra }
. I am somewhat out of my depth here, so after some searching I decided it would be best to ask for help. Do you know why it gives this mistake and could one do anything to solve it? Note that the output method shouldn’t be changed, since it is essentially the one used by l3build.
Many thanks!
I can offer an expandable mechanism UD@CheckWhetherLeadingTokens
by means of which you can have LaTeX check by means of macros that process delimited arguments whether a macro argument's leading tokens form a specific set of tokens.
UD@CheckWhetherLeadingTokens
is different from @ifnextchar
/kernel@ifnextchar
in several aspects:
UD@CheckWhetherLeadingTokens
is expandable.UD@CheckWhetherLeadingTokens
does not "look ahead" at the next token in the token-stream. Instead it does "look" at the first tokens of a macro-argument.(Both with @ifnextchar
/kernel@ifnextchar
and with UD@CheckWhetherLeadingTokens
you may need to pay attention when uppercase
/lowercase
/MakeUppercase
/MakeLowercase
and the like play a rôle.)
documentclass{article}
makeatletter
%==========[code for checking leading token-sequences in arguments]============
%% Check whether argument is empty:
%%.............................................................................
%% UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
newcommandUD@CheckWhetherNull[1]{%
romannumeral0expandafter@secondoftwostring{expandafter
@secondoftwoexpandafter{expandafter{string#1}expandafter
@secondoftwostring}expandafter@firstoftwoexpandafter{expandafter
@secondoftwostring}@firstoftwoexpandafter{} @secondoftwo}%
{@firstoftwoexpandafter{} @firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Exchange two arguments. (From each argument an outermost level of
%% surrounding braces will be removed if present.)
%%-----------------------------------------------------------------------------
newcommandUD@Exchange[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Check whether argument's leading tokens form a specific
%% token-sequence that does not contain explicit character tokens of
%% category code 1 or 2:
%%.............................................................................
%% UD@CheckWhetherLeadingTokens{<argument which is to be checked>}%
%% {<a <token sequence> without explicit
%% character tokens of category code
%% 1 or 2>}%
%% {a <single non-space token> that does
%% _not_ occur in <token sequence> >}%
%% {<internal token-check-macro>}%
%% {<tokens to be delivered in case
%% <argument which is to be checked> has
%% <token sequence> as leading tokens>}%
%% {<tokens to be delivered in case
%% <argument which is to be checked>
%% does not have <token sequence> as
%% leading tokens>}%
newcommandUD@CheckWhetherLeadingTokens[4]{%
romannumeral0UD@CheckWhetherNull{#1}%
{UD@Exchange{ }expandafter@secondoftwo}%
{expandafter@secondoftwostring{expandafter
UD@@CheckWhetherLeadingTokens#4#3#1#2}{}}%
}%
newcommandUD@@CheckWhetherLeadingTokens[1]{%
expandafterUD@CheckWhetherNullexpandafter{@firstoftwo{}#1}%
{UD@Exchange{@firstoftwo}}{UD@Exchange{@secondoftwo}}%
{UD@Exchange{ }{expandafterexpandafterexpandafterexpandafter
expandafterexpandafterexpandafter}expandafterexpandafter
expandafter}expandafter@secondoftwoexpandafter{string}%
}%
%%-----------------------------------------------------------------------------
%% UD@internaltokencheckdefiner{<internal token-check-macro>}%
%% {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%-----------------------------------------------------------------------------
newcommandUD@internaltokencheckdefiner[2]{%
@ifdefinable#1{longdef#1##1#2{{##1}}}%
}%
%=======[end of code for checking leading token-sequences in arguments]=========
UD@internaltokencheckdefiner{zcheck}{z}%
newcommandlookahead[1]{%
UD@CheckWhetherLeadingTokens{#1}{z}{.}{zcheck}{hello}{goodbye} #1%
}%
makeatother
begin{document}
immediatewrite128{ble ble lookahead{y bla} blu blu}
immediatewrite128{ble ble lookahead{{z} bla} blu blu}
immediatewrite128{ble ble lookahead{z bla} blu blu}
end{document}
With the example above I get this on the terminal:
ble ble goodbye y bla blu blu
ble ble goodbye {z} bla blu blu
ble ble hello z bla blu blu
Another approach could be having lookahead
perform a brace-hack for removing the opening-brace before calling another macro lookaheadb
for actually performing the lookahead via @ifnextchar
and having @ifnextchar
perform another brace-hack for adding an opening-brace and calling immediatewrite
on the argument:
documentclass{article}
makeatletter
newcommandlookahead{%
expandafterexpandafterexpandafterlookaheadbexpandafter@gobblestring
}%
newcommandlookaheadb{%
@ifnextchar{z}%
{immediatewrite128expandafterexpandafterexpandafter{expandafter@gobblestring}hello }%
{immediatewrite128expandafterexpandafterexpandafter{expandafter@gobblestring}goodbye }%
}%
makeatother
begin{document}
lookahead{y bla bla bla}
lookahead{{z} bla bla bla}
lookahead{z bla bla bla}
end{document}
With the example above I get this on the terminal:
goodbye y bla bla bla
goodbye {z} bla bla bla
hello z bla bla bla
With this approach lookahead
cannot be nested inside the write
command but is calling the write
-command.
Answered by Ulrich Diez on April 15, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP