Expanding macro twice












3















How would you expand a macro twice in LaTeX 2 (or 2epsilon). I am aware of the question What is the preferred way of expanding twice in expl3?, but I'm curious as to how you'd do it in LaTeX.



I'd like to point out that I suspect that if you actually need to do this in your code, you'd probably want to reformulate your code and not find a way to do this. However, I'm still curious for educational purposes.



Below is my (failing) attempt



documentclass{article}
makeatletter
% Command for printing stuff to the error log
definspect#1{@latex@warning{string#1:meaning#1}}
makeatother
defa{3}
defb{2a}
defc{1b}
% I want to obtain a macro containing "12a" from using only c
% Expand once
edefexpandedOnce{unexpandedexpandafter{c}}
inspectexpandedOnce
%% ^ produces 1b in the error log
expandafterexpandafteredefexpandafterexpandedTwice{unexpandedexpandafter{expandedOnce}}
inspectexpandedTwice
%% ^ Also produces 1b in the error log, but I'd want it to
%% produce 12a
begin{document}
~
end{document}









share|improve this question


















  • 2





    you haven't really defined what expanding twice means, normally i'd take it to mean expandafterexpandafterexpandafterc but 1 isn't expandable so that gives you 1b you say you want 12a but do you want to expand all tokens in c by one step, or just the first expandable token. (clearly you don't mean the first token, as I note above.) what would you want if the definition of c was defc{1b1b} ?

    – David Carlisle
    Nov 24 '18 at 21:38













  • Good question! As I note in my original question, I don't have a specific use case. I'm mostly curious about expanding all tokens in c by one step though.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:40











  • @DavidCarlisle, for the case when the definition is defc{1b1b}, I then guess I'd want the result to be 12a12a because then, since 1 can't be expanded further, it stays as a 1 and b is 2a after one expansion.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:43













  • @DavidCarlisle No, wait. That's not twice.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:45






  • 1





    I posted an answer that I think matches what you ask for but it is not at all the expansion order that tex would use. You are expanding everything in the list first by one step, then expanding everything in the resulting list, TeX would fully expand the first token in as many steps as it took before expanding the second token so tokens at teh end of the original list may not be exanded until many expansion steps, or in fact may never be expanded at all.

    – David Carlisle
    Nov 24 '18 at 21:51
















3















How would you expand a macro twice in LaTeX 2 (or 2epsilon). I am aware of the question What is the preferred way of expanding twice in expl3?, but I'm curious as to how you'd do it in LaTeX.



I'd like to point out that I suspect that if you actually need to do this in your code, you'd probably want to reformulate your code and not find a way to do this. However, I'm still curious for educational purposes.



Below is my (failing) attempt



documentclass{article}
makeatletter
% Command for printing stuff to the error log
definspect#1{@latex@warning{string#1:meaning#1}}
makeatother
defa{3}
defb{2a}
defc{1b}
% I want to obtain a macro containing "12a" from using only c
% Expand once
edefexpandedOnce{unexpandedexpandafter{c}}
inspectexpandedOnce
%% ^ produces 1b in the error log
expandafterexpandafteredefexpandafterexpandedTwice{unexpandedexpandafter{expandedOnce}}
inspectexpandedTwice
%% ^ Also produces 1b in the error log, but I'd want it to
%% produce 12a
begin{document}
~
end{document}









share|improve this question


















  • 2





    you haven't really defined what expanding twice means, normally i'd take it to mean expandafterexpandafterexpandafterc but 1 isn't expandable so that gives you 1b you say you want 12a but do you want to expand all tokens in c by one step, or just the first expandable token. (clearly you don't mean the first token, as I note above.) what would you want if the definition of c was defc{1b1b} ?

    – David Carlisle
    Nov 24 '18 at 21:38













  • Good question! As I note in my original question, I don't have a specific use case. I'm mostly curious about expanding all tokens in c by one step though.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:40











  • @DavidCarlisle, for the case when the definition is defc{1b1b}, I then guess I'd want the result to be 12a12a because then, since 1 can't be expanded further, it stays as a 1 and b is 2a after one expansion.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:43













  • @DavidCarlisle No, wait. That's not twice.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:45






  • 1





    I posted an answer that I think matches what you ask for but it is not at all the expansion order that tex would use. You are expanding everything in the list first by one step, then expanding everything in the resulting list, TeX would fully expand the first token in as many steps as it took before expanding the second token so tokens at teh end of the original list may not be exanded until many expansion steps, or in fact may never be expanded at all.

    – David Carlisle
    Nov 24 '18 at 21:51














3












3








3








How would you expand a macro twice in LaTeX 2 (or 2epsilon). I am aware of the question What is the preferred way of expanding twice in expl3?, but I'm curious as to how you'd do it in LaTeX.



I'd like to point out that I suspect that if you actually need to do this in your code, you'd probably want to reformulate your code and not find a way to do this. However, I'm still curious for educational purposes.



Below is my (failing) attempt



documentclass{article}
makeatletter
% Command for printing stuff to the error log
definspect#1{@latex@warning{string#1:meaning#1}}
makeatother
defa{3}
defb{2a}
defc{1b}
% I want to obtain a macro containing "12a" from using only c
% Expand once
edefexpandedOnce{unexpandedexpandafter{c}}
inspectexpandedOnce
%% ^ produces 1b in the error log
expandafterexpandafteredefexpandafterexpandedTwice{unexpandedexpandafter{expandedOnce}}
inspectexpandedTwice
%% ^ Also produces 1b in the error log, but I'd want it to
%% produce 12a
begin{document}
~
end{document}









share|improve this question














How would you expand a macro twice in LaTeX 2 (or 2epsilon). I am aware of the question What is the preferred way of expanding twice in expl3?, but I'm curious as to how you'd do it in LaTeX.



I'd like to point out that I suspect that if you actually need to do this in your code, you'd probably want to reformulate your code and not find a way to do this. However, I'm still curious for educational purposes.



Below is my (failing) attempt



documentclass{article}
makeatletter
% Command for printing stuff to the error log
definspect#1{@latex@warning{string#1:meaning#1}}
makeatother
defa{3}
defb{2a}
defc{1b}
% I want to obtain a macro containing "12a" from using only c
% Expand once
edefexpandedOnce{unexpandedexpandafter{c}}
inspectexpandedOnce
%% ^ produces 1b in the error log
expandafterexpandafteredefexpandafterexpandedTwice{unexpandedexpandafter{expandedOnce}}
inspectexpandedTwice
%% ^ Also produces 1b in the error log, but I'd want it to
%% produce 12a
begin{document}
~
end{document}






macros expansion






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 24 '18 at 21:17









Andreas Storvik StraumanAndreas Storvik Strauman

2,533418




2,533418








  • 2





    you haven't really defined what expanding twice means, normally i'd take it to mean expandafterexpandafterexpandafterc but 1 isn't expandable so that gives you 1b you say you want 12a but do you want to expand all tokens in c by one step, or just the first expandable token. (clearly you don't mean the first token, as I note above.) what would you want if the definition of c was defc{1b1b} ?

    – David Carlisle
    Nov 24 '18 at 21:38













  • Good question! As I note in my original question, I don't have a specific use case. I'm mostly curious about expanding all tokens in c by one step though.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:40











  • @DavidCarlisle, for the case when the definition is defc{1b1b}, I then guess I'd want the result to be 12a12a because then, since 1 can't be expanded further, it stays as a 1 and b is 2a after one expansion.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:43













  • @DavidCarlisle No, wait. That's not twice.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:45






  • 1





    I posted an answer that I think matches what you ask for but it is not at all the expansion order that tex would use. You are expanding everything in the list first by one step, then expanding everything in the resulting list, TeX would fully expand the first token in as many steps as it took before expanding the second token so tokens at teh end of the original list may not be exanded until many expansion steps, or in fact may never be expanded at all.

    – David Carlisle
    Nov 24 '18 at 21:51














  • 2





    you haven't really defined what expanding twice means, normally i'd take it to mean expandafterexpandafterexpandafterc but 1 isn't expandable so that gives you 1b you say you want 12a but do you want to expand all tokens in c by one step, or just the first expandable token. (clearly you don't mean the first token, as I note above.) what would you want if the definition of c was defc{1b1b} ?

    – David Carlisle
    Nov 24 '18 at 21:38













  • Good question! As I note in my original question, I don't have a specific use case. I'm mostly curious about expanding all tokens in c by one step though.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:40











  • @DavidCarlisle, for the case when the definition is defc{1b1b}, I then guess I'd want the result to be 12a12a because then, since 1 can't be expanded further, it stays as a 1 and b is 2a after one expansion.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:43













  • @DavidCarlisle No, wait. That's not twice.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:45






  • 1





    I posted an answer that I think matches what you ask for but it is not at all the expansion order that tex would use. You are expanding everything in the list first by one step, then expanding everything in the resulting list, TeX would fully expand the first token in as many steps as it took before expanding the second token so tokens at teh end of the original list may not be exanded until many expansion steps, or in fact may never be expanded at all.

    – David Carlisle
    Nov 24 '18 at 21:51








2




2





you haven't really defined what expanding twice means, normally i'd take it to mean expandafterexpandafterexpandafterc but 1 isn't expandable so that gives you 1b you say you want 12a but do you want to expand all tokens in c by one step, or just the first expandable token. (clearly you don't mean the first token, as I note above.) what would you want if the definition of c was defc{1b1b} ?

– David Carlisle
Nov 24 '18 at 21:38







you haven't really defined what expanding twice means, normally i'd take it to mean expandafterexpandafterexpandafterc but 1 isn't expandable so that gives you 1b you say you want 12a but do you want to expand all tokens in c by one step, or just the first expandable token. (clearly you don't mean the first token, as I note above.) what would you want if the definition of c was defc{1b1b} ?

– David Carlisle
Nov 24 '18 at 21:38















Good question! As I note in my original question, I don't have a specific use case. I'm mostly curious about expanding all tokens in c by one step though.

– Andreas Storvik Strauman
Nov 24 '18 at 21:40





Good question! As I note in my original question, I don't have a specific use case. I'm mostly curious about expanding all tokens in c by one step though.

– Andreas Storvik Strauman
Nov 24 '18 at 21:40













@DavidCarlisle, for the case when the definition is defc{1b1b}, I then guess I'd want the result to be 12a12a because then, since 1 can't be expanded further, it stays as a 1 and b is 2a after one expansion.

– Andreas Storvik Strauman
Nov 24 '18 at 21:43







@DavidCarlisle, for the case when the definition is defc{1b1b}, I then guess I'd want the result to be 12a12a because then, since 1 can't be expanded further, it stays as a 1 and b is 2a after one expansion.

– Andreas Storvik Strauman
Nov 24 '18 at 21:43















@DavidCarlisle No, wait. That's not twice.

– Andreas Storvik Strauman
Nov 24 '18 at 21:45





@DavidCarlisle No, wait. That's not twice.

– Andreas Storvik Strauman
Nov 24 '18 at 21:45




1




1





I posted an answer that I think matches what you ask for but it is not at all the expansion order that tex would use. You are expanding everything in the list first by one step, then expanding everything in the resulting list, TeX would fully expand the first token in as many steps as it took before expanding the second token so tokens at teh end of the original list may not be exanded until many expansion steps, or in fact may never be expanded at all.

– David Carlisle
Nov 24 '18 at 21:51





I posted an answer that I think matches what you ask for but it is not at all the expansion order that tex would use. You are expanding everything in the list first by one step, then expanding everything in the resulting list, TeX would fully expand the first token in as many steps as it took before expanding the second token so tokens at teh end of the original list may not be exanded until many expansion steps, or in fact may never be expanded at all.

– David Carlisle
Nov 24 '18 at 21:51










4 Answers
4






active

oldest

votes


















4














Newer new answer



The following expands every expandable token once and if that token needs arguments they are supplied (doesn't work for delimited arguments like with deffoo#1.{#1}). Note that this is not necessarily how TeX would expand things. I created it mostly because I was curious how one could do it.



documentclass{article}

newcommandfoo{bazA}
newcommandbazA{bazB}
newcommandbazB{bar}

defa{3}
defb{2a}
makeatletter
defc{1b 9}
makeatother

defafterfi#1fi{fi#1}
defafterelsefi#1else#2fi{fi#1}
defafterorfi#1or#2fi{fi#1}
defafterfiBfi#1#2{fi#2}
defafterelsefiAelse#1fi#2#3{fi#2}
makeatletter
newcommandifempty[1]%>>>
{%
ifrelaxdetokenize{#1}relax
afterelsefiA
else
afterfiB
fi
}%<<<
newcommandifdigit[1]%>>>
{%
ifx1#1afterelsefiA
elseifdigit@b2#1%
elseifdigit@b3#1%
elseifdigit@b4#1%
elseifdigit@b5#1%
elseifdigit@b6#1%
elseifdigit@b7#1%
elseifdigit@b8#1%
elseifdigit@b9#1%
elseifdigit@b0#1%
elseafterfiB
fi
}%<<<
newcommandifdigit@b[2]%>>>
{%
fiifx#1#2afterelsefiA
}%<<<
defq@stop{q@stopError}
defq@mark{q@markError}
longdefexpandingloop@a#1#%>>>
{%
expandingloop@b#1q@stop
}%<<<
longdefexpandingloop@b#1%>>>
{%
ifxq@stop#1%
afterelsefiexpandingloop@c
else
afterfiexpandingloop@d#1%
fi
}%<<<
newcommandexpandingloop@c[1]%>>>
{%
ifempty{#1}
{{}expandingloop@a}
{%
ifxq@stop#1%
else
afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
fi
}%
}%<<<
newcommandexpandingloop@d[1]%>>>
{%
ifcasetestargs{#1}
afterorfiunexpandedexpandafter{#1}expandingloop@b%
orafterorfiexpandingloop@d@i{#1}%
orafterorfiexpandingloop@d@ii{#1}%
orafterorfiexpandingloop@d@iii{#1}%
orafterorfiexpandingloop@d@iv{#1}%
orafterorfiexpandingloop@d@v{#1}%
orafterorfiexpandingloop@d@vi{#1}%
orafterorfiexpandingloop@d@vii{#1}%
orafterorfiexpandingloop@d@viii{#1}%
orafterfiexpandingloop@d@ix{#1}%
orDelimitedArgumentError
fi
}%<<<
newcommandexpandingloop@d@group[3]%>>>
{%
ifxq@stop#3%
OutOfArgumentsError
else
afterfiexpandingloop@d@group@a{#1}{#2{#3}}%
fi
}%<<<
defexpandingloop@d@group@a#1#2#3#%>>>
{%
#1{#2}#3q@stop
}%<<<
newcommandexpandingloop@d@exec[1]%>>>
{%
unexpandedexpandafter{#1}expandingloop@b
}%<<<
newcommandexpandingloop@d@i[2]%>>>
{%
ifxq@stop#2%
afterelsefiexpandingloop@d@group{expandingloop@d@exec}{#1}%
else
afterfiexpandingloop@d@exec{#1#2}%
fi
}%<<<
newcommanddef@expandingloop@d@[2]%>>>
{%
expandafteredefcsname expandingloop@d@#1endcsname##1##2%
{%
unexpanded{ifxq@stop}##2%
unexpanded{afterelsefiexpandingloop@d@group}%
expandafternoexpandcsname expandingloop@d@#2endcsname{##1}%
unexpanded{else
afterfi}%
expandafternoexpandcsname expandingloop@d@#2endcsname{##1##2}%
noexpandfi
}%
}%<<<
def@expandingloop@d@{ix}{viii}
def@expandingloop@d@{viii}{vii}
def@expandingloop@d@{vii}{vi}
def@expandingloop@d@{vi}{v}
def@expandingloop@d@{v}{iv}
def@expandingloop@d@{iv}{iii}
def@expandingloop@d@{iii}{ii}
def@expandingloop@d@{ii}{i}
newcommandsingleallexpand[1]%>>>
{%
edef#1{expandafterexpandingloop@a#1{q@stop}}%
}%<<<
newcommandtestargs[1]%>>>
{%
expandaftertestargs@ameaning#1->q@markq@stop%
}%<<<
longdeftestargs@a#1->#2#3q@stop%>>>
{%
ifxq@mark#2%
afterelsefi0%
else
afterfitestargs@b#1q@stop
fi
}%<<<
longdeftestargs@b#1:#2q@stop%>>>
{%
ifempty{#2}
{0}
{testargs@c#2q@stop}%
}%<<<
begingroup
catcode`#=12
defzz{endgroupdefmyhashtag{#}}
zz
longedeftestargs@c#1#2#3q@stop%>>>
{%
noexpandifxmyhashtag#1%
noexpandifdigit{#2}
{%
noexpandifempty{#3}
{noexpandafterelsefi#2}
{noexpandafterelsefinoexpandtestargs@c#3noexpandq@stop}%
}
{10}% macros don't take >9 arguments so this is a great error flag
noexpandelse
10% macros don't take >9 arguments so this is a great error flag
noexpandfi
}%<<<
makeatother

newcommandMeaning[1]{texttt{meaning#1}}

begin{document}
noindent
For verb|foo|:

lettmpfoo
Unexpanded:
Meaningtmp

singleallexpandtmp
Expanded once:
Meaningtmp

singleallexpandtmp
Expanded twice:
Meaningtmp

noindent
For verb|c|:

lettmpc
Unexpanded:
Meaningtmp

singleallexpandtmp
Expanded once:
Meaningtmp

singleallexpandtmp
Expanded twice:
Meaningtmp
end{document}


New answer



The following expands every token in tmp (which is what you want, I hope) in a more reliable way. I didn't test it thoroughly though. It should only work for contents that don't take arguments.



documentclass{article}

newcommandfoo{bazA}
newcommandbazA{bazB}
newcommandbazB{bar}

defa{3}
defb{2a}
defc{1{b}}

defafterfi#1fi{fi#1}
makeatletter
defq@stop{q@stop}
defexpandingloop@a#1#%
{%
expandingloop@b#1q@stop
expandingloop@c
}
defexpandingloop@b#1%
{%
ifxq@stop#1%
else
afterfiunexpandedexpandafter{#1}expandingloop@b
fi
}
newcommandexpandingloop@c[1]
{%
ifxq@stop#1%
else
afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
fi
}
newcommandsingleallexpand[1]
{%
edef#1{expandafterexpandingloop@a#1{q@stop}}%
}
makeatother

newcommandMeaning[1]{texttt{meaning#1}}


begin{document}
noindent
For verb|foo|:

lettmpfoo
Unexpanded:
Meaningtmp

singleallexpandtmp
Expanded once:
Meaningtmp

singleallexpandtmp
Expanded twice:
Meaningtmp

noindent
For verb|c|:

lettmpc
Unexpanded:
Meaningtmp

singleallexpandtmp
Expanded once:
Meaningtmp

singleallexpandtmp
Expanded twice:
Meaningtmp
end{document}


enter image description here





Old answer



Both of the following only expand the first token.



You can use edeffooA{unexpandedexpandafterexpandafterexpandafter{fooB}} to define fooA to be the same as a fooB expanded twice.



Doing stuff with a temporary macro one could do something like the following.



documentclass{article}

newcommandfoo{bazA}
newcommandbazA{bazB}
newcommandbazB{bar}

newcommandsingleexpand[1]
{%
edef#1{unexpandedexpandafterexpandafterexpandafter{#1}}%
}

newcommandMeaning[1]{texttt{meaning#1}}


begin{document}
lettmpfoo
Unexpanded:
Meaningtmp

singleexpandtmp
Expanded once:
Meaningtmp

singleexpandtmp
Expanded twice:
Meaningtmp
end{document}


Being evil when the argument contains a group (but it works in the minimal example, everything else is a matter of adding an infinite number of tests):



defafterfi#1fi{fi#1}
defexpandingloop#1#2endexpandingloop
{%
unexpandedexpandafter{#1}%
ifrelaxdetokenize{#2}relax
else
afterfiexpandingloop#2endexpandingloop
fi
}
newcommandsingleallexpand[1]
{%
edef#1{expandafterexpandingloop#1endexpandingloop}%
}





share|improve this answer


























  • Sorry. I really should have explicitly said that it's not only the first expandable token.

    – Andreas Storvik Strauman
    Nov 24 '18 at 21:45



















5














I get



> zz=macro:
->12a 12a .


on the terminal from etex (or pdftex) from



defa{3}
defb{2a}
defc{1b1b}
defafterfi#1fi{fi#1}
deffoo#1{ifxrelax#1elseafterfiexpandafterunexpandedexpandafter{#1}foofi}
edefzz{expandafterfoocrelax}

showzz

bye




Note that this is the expansion order that you asked for, as far as I can tell but is not the order that TeX would use normally so it isnt really "expanding twice"



Consider



defa{b} defb#1{}  defc{zzzzz}
defz{ac}


by your definition I think you want to expand a and c once in the first step so getting a "first expansion" of z as b zzzzz then on a second step expand b so get zzzz.



However TeX would fully expand the first token at each stage, so in the first step get bc then in the second step get an empty list. c would never be expanded at all by TeX.






share|improve this answer

































    1














    I think a reliable algorithm for expanding outgoing from an arbitrary set of tokens at most k times is not possible:



    Expanding at most one time is already a problem:



    You'd need an algorithm which recursively iterates on a &langle;list of not yet expanded tokens&rangle; and maintains a &langle;list of already expanded tokens&rangle; as follows:





    Step 1:



    Check whether the &langle;list of not yet expanded tokens&rangle; is empty.



    If so: Deliver the &langle;list of already expanded tokens&rangle;.



    If not so:





    • In case the first element/the first token of the &langle;list of
      not yet expanded tokens&rangle;
      is not expandable, remove it from
      the &langle;list of not yet expanded tokens&rangle; and add it
      at the end of the &langle;list of already expanded
      tokens&rangle;
      .



      In case the first element/the first token of the
      &langle;list of not yet expanded tokens&rangle; is expandable,
      expand it and remove the result of that expansion from the
      &langle;list of not yet expanded tokens&rangle; and add the
      result of that expansion at the end of the &langle;list of already
      expanded tokens&rangle;



    • Repeat Step 1.




    One crucial point hereby is "removing the result of that expansion from the &langle;list of not yet expanded tokens&rangle; and adding the result of that expansion at the end of the &langle;list of already expanded tokens&rangle;".



    That point is crucial because it implies that after expansion you need to detect which tokens belong to the result of that expansion and which tokens were already in the &langle;list of not yet expanded tokens&rangle; before that expansion took place.



    Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}

    , while the &langle;list of not yet expanded tokens&rangle; holds the following content:
    macro ABC Whatsoever



    Now you need to have macro expanded once. After that, the &langle;list of not yet expanded tokens&rangle; holds the following content:
    ABC Whatsoever.



    Now you need to move the result from expanding macro towards the &langle;list of already expanded tokens&rangle;.



    In this case the result of expanding macro is formed by the tokens ABC.



    How to detect that these ABC are the replacement-text/the expansion-result from expanding macro and thus are not the same as the ABC that before expansion were in the &langle;list of not yet expanded tokens&rangle;?



    (Parsing the result of meaning with every expandable token for finding out whether it is a macro that processes arguments does not deliver reliable information about the parameter-texts of macros because with meaning you don't have reliable information about the category-codes of tokens / about whether a set of delivered characters denotes a set of character tokens (of whatsoever category code) or a control sequence...)



    Another crucial point is that you'd need to iterate "token-wise" while macros usually work "argument-wise".





    In your special case, where you already know about definitions and tokens delivered by expansion, you can, e.g., do:



    defa{3}
    defb{2a}
    defc{1b}
    % You wish to obtain a macro containing "12a" from using only c


    % expandaf-% expandaf-%
    % ter- % ter- %
    % chain 1 % chain 2 %
    % | % | %
    expandafterexpandafter
    expandafter def
    expandafterexpandafter
    expandafter expandedTwice
    expandafterexpandafter
    expandafter {%
    expandafterexpandafter
    c}


    expandafter-chain 1 delivers:



    % expandaf-%
    % ter- %
    % chain 2 %
    % | %
    expandafter
    def
    expandafter
    expandedTwice
    expandafter
    {%
    expandafter
    1b}


    expandafter-chain 2 delivers:



    def
    expandedTwice
    {%
    12a}


    (In case you are not familiar to expandafter:



    expandafter is an expandable primitive which works on the next and on the next but one token:



    In case the next but one token is expandable, the replacement-text of
    expandafter&langle;next token&rangle;&langle;next but one token&rangle;

    will be
    &langle;next token&rangle;&langle;top-level-expansion of next but one token&rangle;.



    In case the next but one token is not expandable, the replacement-text of
    expandafter&langle;next token&rangle;&langle;next but one token&rangle;

    will be
    &langle;next token&rangle;&langle;next but one token&rangle;.



    In other words: (La)TeX considers the expandafter-work done and removes the expandafter from the token-stream when top-level-expanding the next-but-one token is finished.

    That's why you can have expandafter-chains for "hopping" over tokens that shall not be expanded.



    E.g., if you have deffoo{bar}, and do
    expandafter 1expandafter 2expandafter 3foo

    , you will get
    123bar:



    Carrying out the first expandafter causes the second expandafter to be carried out. Hereby "carrying out the second expandafter" is considered an aspect of carrying out the first expandafter.

    Carrying out the second expandafter in turn causes the third expandafter to be carried out. Hereby "carrying out the third expandafter" is considered an aspect of carrying out the second expandafter.
    The third expandafter causes foo to be top-level-expanded.

    When the top-level-expansion of foo is delivered, (La)TeX will consider the expansion-work of the third expandafter done.

    This expansion-work was initiated by the second expndafter.
    As the expansion-work initiated by the second expandafter is done, now the expansion-work of the second expandafter is done.
    The expansion-work of the second expandafter was initiated by the first expandafter.

    As the expansion-work initiated by the first expandafter is done, now the expansion-work of the first expandafter is done.)





    But if you have, e.g.,



    catcode`(=1 %
    catcode`)=2 %
    defa{3}
    defb{2a}
    defc{11111(1)11111b}


    , and wish to obtain 11111(1)111112a—parentheses still of catcode 1 / 2 —outgoing from c, this will probably turn out an interesting task.





    By the way 1: The methods of choice for obtaining the result of expansion highly depend on the context:



    Within a "pure expansion context", i.e., e.g., within csname..endcsname or within write{...} or within edef{..} you cannot have LaTeX define temporary macros/you cannot have LaTeX perform whatsoever assignments (with the exception of the result of csname..endcsname locally assigning the meaning of the relax-primitive in case the control-sequence-token constructed is undefined).



    By the way 2: edef/ xdef is not reliable in all situations.

    E.g., look at:



    edeftest{%
    Where does the assignment end? Here? iffalse{fi}%
    {iffalse}fi Or here?%
    }%
    par
    meaningtest





    share|improve this answer

































      0














      I'm fairly certain that the following will do expansion of the macros as described in the original question: (In hindsight, using semicolon as termination char might not be the best design choice). Maybe I'm missing something as to why this will not work?



      documentclass{article}
      makeatletter
      defa{3}
      defb{2a}
      defc{1b}
      def@iterator{%
      % Expects to be followed by a list of tokens terminated
      % by a semicolon. If the next character is not a semicolon
      % then consider it a token to expand.
      % If the next character is a semicolon then we're done iterating
      % and can finalising procedures
      @ifnextchar;@finishIter@processnext%
      }
      newcommandtmp@exptok{}
      def@processnext#1{%
      % Proces one token and add it to our macro containing
      % tmp@exptok contains all the tokens expanded once.
      % So we're now adding this next token.
      xdeftmp@exptok{unexpandedexpandafter{tmp@exptok}unexpandedexpandafter{#1}}@iterator%
      }
      def@finishIter;{globalletexpandedResulttmp@exptokgdeftmp@exptok{}}
      newcommandexpandtwice[2]{%
      % First do one expansion
      @iterator#1;%
      % Now all tokens are expanded once and contained in expandedResult
      % Now we reapply it to re-expand every token once again
      expandafter@iteratorexpandedResult;%
      % Now store the result in the macro given by the user
      let#2expandedResult%
      }
      makeatother
      expandtwice{cc}{cTwiceExpanded}
      % cc -> {1b}{1b} -> 1{2a}1{2a}
      begin{document}
      texttt{meaningcTwiceExpanded}%<- now contains 12a12a
      end{document}


      Edit: There are of course some special cases like unexpandable macros like textbf which would fail (could potentially be fixed though, by looking for protect after the expansion). Also if you used group brackets ({}), a problem would arise. The latter one probably has a solution with checking the next character for bgroup or something similar.



      Edit 2: To fix the grouping problem:



      def@itergroup{%
      expandafter@iterator@firstofone
      }
      def@iterator{%
      @ifnextcharbgroup{@itergroup}{@ifnextchar;@finishIter@processnext}%
      }


      Also, as the OP, I'll be honest and say I haven't yet taken the time to understand how most of the other provided answers work, but I will do so in the near future and select an answer.






      share|improve this answer


























      • @UlrichDiez Yup. You're right.

        – Andreas Storvik Strauman
        Nov 26 '18 at 20:52











      • Your @processnext is not suitable for arbitrary sets of tokens: In case one of the tokens processed by @processnextis a macro that processes arguments, @processnext needs to fetch these arguments for the xdef, too...

        – Ulrich Diez
        Nov 26 '18 at 21:27











      • @AndreasStorvikStrauman take a look at my answer, which checks for arguments and fetches them (unfortunately it is only working for macros with undelimited arguments, so still not working for arbitrary tokens). Perhaps if I completely change the approach from being fully expandable inside of an edef I could work that out.

        – Skillmon
        Nov 27 '18 at 11:39











      • @Skillmon I will. Sorry, just very hectic these days. I really want to understand it before I accept it :)

        – Andreas Storvik Strauman
        Dec 3 '18 at 8:44











      Your Answer








      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "85"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f461620%2fexpanding-macro-twice%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      4














      Newer new answer



      The following expands every expandable token once and if that token needs arguments they are supplied (doesn't work for delimited arguments like with deffoo#1.{#1}). Note that this is not necessarily how TeX would expand things. I created it mostly because I was curious how one could do it.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      defa{3}
      defb{2a}
      makeatletter
      defc{1b 9}
      makeatother

      defafterfi#1fi{fi#1}
      defafterelsefi#1else#2fi{fi#1}
      defafterorfi#1or#2fi{fi#1}
      defafterfiBfi#1#2{fi#2}
      defafterelsefiAelse#1fi#2#3{fi#2}
      makeatletter
      newcommandifempty[1]%>>>
      {%
      ifrelaxdetokenize{#1}relax
      afterelsefiA
      else
      afterfiB
      fi
      }%<<<
      newcommandifdigit[1]%>>>
      {%
      ifx1#1afterelsefiA
      elseifdigit@b2#1%
      elseifdigit@b3#1%
      elseifdigit@b4#1%
      elseifdigit@b5#1%
      elseifdigit@b6#1%
      elseifdigit@b7#1%
      elseifdigit@b8#1%
      elseifdigit@b9#1%
      elseifdigit@b0#1%
      elseafterfiB
      fi
      }%<<<
      newcommandifdigit@b[2]%>>>
      {%
      fiifx#1#2afterelsefiA
      }%<<<
      defq@stop{q@stopError}
      defq@mark{q@markError}
      longdefexpandingloop@a#1#%>>>
      {%
      expandingloop@b#1q@stop
      }%<<<
      longdefexpandingloop@b#1%>>>
      {%
      ifxq@stop#1%
      afterelsefiexpandingloop@c
      else
      afterfiexpandingloop@d#1%
      fi
      }%<<<
      newcommandexpandingloop@c[1]%>>>
      {%
      ifempty{#1}
      {{}expandingloop@a}
      {%
      ifxq@stop#1%
      else
      afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
      fi
      }%
      }%<<<
      newcommandexpandingloop@d[1]%>>>
      {%
      ifcasetestargs{#1}
      afterorfiunexpandedexpandafter{#1}expandingloop@b%
      orafterorfiexpandingloop@d@i{#1}%
      orafterorfiexpandingloop@d@ii{#1}%
      orafterorfiexpandingloop@d@iii{#1}%
      orafterorfiexpandingloop@d@iv{#1}%
      orafterorfiexpandingloop@d@v{#1}%
      orafterorfiexpandingloop@d@vi{#1}%
      orafterorfiexpandingloop@d@vii{#1}%
      orafterorfiexpandingloop@d@viii{#1}%
      orafterfiexpandingloop@d@ix{#1}%
      orDelimitedArgumentError
      fi
      }%<<<
      newcommandexpandingloop@d@group[3]%>>>
      {%
      ifxq@stop#3%
      OutOfArgumentsError
      else
      afterfiexpandingloop@d@group@a{#1}{#2{#3}}%
      fi
      }%<<<
      defexpandingloop@d@group@a#1#2#3#%>>>
      {%
      #1{#2}#3q@stop
      }%<<<
      newcommandexpandingloop@d@exec[1]%>>>
      {%
      unexpandedexpandafter{#1}expandingloop@b
      }%<<<
      newcommandexpandingloop@d@i[2]%>>>
      {%
      ifxq@stop#2%
      afterelsefiexpandingloop@d@group{expandingloop@d@exec}{#1}%
      else
      afterfiexpandingloop@d@exec{#1#2}%
      fi
      }%<<<
      newcommanddef@expandingloop@d@[2]%>>>
      {%
      expandafteredefcsname expandingloop@d@#1endcsname##1##2%
      {%
      unexpanded{ifxq@stop}##2%
      unexpanded{afterelsefiexpandingloop@d@group}%
      expandafternoexpandcsname expandingloop@d@#2endcsname{##1}%
      unexpanded{else
      afterfi}%
      expandafternoexpandcsname expandingloop@d@#2endcsname{##1##2}%
      noexpandfi
      }%
      }%<<<
      def@expandingloop@d@{ix}{viii}
      def@expandingloop@d@{viii}{vii}
      def@expandingloop@d@{vii}{vi}
      def@expandingloop@d@{vi}{v}
      def@expandingloop@d@{v}{iv}
      def@expandingloop@d@{iv}{iii}
      def@expandingloop@d@{iii}{ii}
      def@expandingloop@d@{ii}{i}
      newcommandsingleallexpand[1]%>>>
      {%
      edef#1{expandafterexpandingloop@a#1{q@stop}}%
      }%<<<
      newcommandtestargs[1]%>>>
      {%
      expandaftertestargs@ameaning#1->q@markq@stop%
      }%<<<
      longdeftestargs@a#1->#2#3q@stop%>>>
      {%
      ifxq@mark#2%
      afterelsefi0%
      else
      afterfitestargs@b#1q@stop
      fi
      }%<<<
      longdeftestargs@b#1:#2q@stop%>>>
      {%
      ifempty{#2}
      {0}
      {testargs@c#2q@stop}%
      }%<<<
      begingroup
      catcode`#=12
      defzz{endgroupdefmyhashtag{#}}
      zz
      longedeftestargs@c#1#2#3q@stop%>>>
      {%
      noexpandifxmyhashtag#1%
      noexpandifdigit{#2}
      {%
      noexpandifempty{#3}
      {noexpandafterelsefi#2}
      {noexpandafterelsefinoexpandtestargs@c#3noexpandq@stop}%
      }
      {10}% macros don't take >9 arguments so this is a great error flag
      noexpandelse
      10% macros don't take >9 arguments so this is a great error flag
      noexpandfi
      }%<<<
      makeatother

      newcommandMeaning[1]{texttt{meaning#1}}

      begin{document}
      noindent
      For verb|foo|:

      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp

      noindent
      For verb|c|:

      lettmpc
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      New answer



      The following expands every token in tmp (which is what you want, I hope) in a more reliable way. I didn't test it thoroughly though. It should only work for contents that don't take arguments.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      defa{3}
      defb{2a}
      defc{1{b}}

      defafterfi#1fi{fi#1}
      makeatletter
      defq@stop{q@stop}
      defexpandingloop@a#1#%
      {%
      expandingloop@b#1q@stop
      expandingloop@c
      }
      defexpandingloop@b#1%
      {%
      ifxq@stop#1%
      else
      afterfiunexpandedexpandafter{#1}expandingloop@b
      fi
      }
      newcommandexpandingloop@c[1]
      {%
      ifxq@stop#1%
      else
      afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
      fi
      }
      newcommandsingleallexpand[1]
      {%
      edef#1{expandafterexpandingloop@a#1{q@stop}}%
      }
      makeatother

      newcommandMeaning[1]{texttt{meaning#1}}


      begin{document}
      noindent
      For verb|foo|:

      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp

      noindent
      For verb|c|:

      lettmpc
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      enter image description here





      Old answer



      Both of the following only expand the first token.



      You can use edeffooA{unexpandedexpandafterexpandafterexpandafter{fooB}} to define fooA to be the same as a fooB expanded twice.



      Doing stuff with a temporary macro one could do something like the following.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      newcommandsingleexpand[1]
      {%
      edef#1{unexpandedexpandafterexpandafterexpandafter{#1}}%
      }

      newcommandMeaning[1]{texttt{meaning#1}}


      begin{document}
      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleexpandtmp
      Expanded once:
      Meaningtmp

      singleexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      Being evil when the argument contains a group (but it works in the minimal example, everything else is a matter of adding an infinite number of tests):



      defafterfi#1fi{fi#1}
      defexpandingloop#1#2endexpandingloop
      {%
      unexpandedexpandafter{#1}%
      ifrelaxdetokenize{#2}relax
      else
      afterfiexpandingloop#2endexpandingloop
      fi
      }
      newcommandsingleallexpand[1]
      {%
      edef#1{expandafterexpandingloop#1endexpandingloop}%
      }





      share|improve this answer


























      • Sorry. I really should have explicitly said that it's not only the first expandable token.

        – Andreas Storvik Strauman
        Nov 24 '18 at 21:45
















      4














      Newer new answer



      The following expands every expandable token once and if that token needs arguments they are supplied (doesn't work for delimited arguments like with deffoo#1.{#1}). Note that this is not necessarily how TeX would expand things. I created it mostly because I was curious how one could do it.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      defa{3}
      defb{2a}
      makeatletter
      defc{1b 9}
      makeatother

      defafterfi#1fi{fi#1}
      defafterelsefi#1else#2fi{fi#1}
      defafterorfi#1or#2fi{fi#1}
      defafterfiBfi#1#2{fi#2}
      defafterelsefiAelse#1fi#2#3{fi#2}
      makeatletter
      newcommandifempty[1]%>>>
      {%
      ifrelaxdetokenize{#1}relax
      afterelsefiA
      else
      afterfiB
      fi
      }%<<<
      newcommandifdigit[1]%>>>
      {%
      ifx1#1afterelsefiA
      elseifdigit@b2#1%
      elseifdigit@b3#1%
      elseifdigit@b4#1%
      elseifdigit@b5#1%
      elseifdigit@b6#1%
      elseifdigit@b7#1%
      elseifdigit@b8#1%
      elseifdigit@b9#1%
      elseifdigit@b0#1%
      elseafterfiB
      fi
      }%<<<
      newcommandifdigit@b[2]%>>>
      {%
      fiifx#1#2afterelsefiA
      }%<<<
      defq@stop{q@stopError}
      defq@mark{q@markError}
      longdefexpandingloop@a#1#%>>>
      {%
      expandingloop@b#1q@stop
      }%<<<
      longdefexpandingloop@b#1%>>>
      {%
      ifxq@stop#1%
      afterelsefiexpandingloop@c
      else
      afterfiexpandingloop@d#1%
      fi
      }%<<<
      newcommandexpandingloop@c[1]%>>>
      {%
      ifempty{#1}
      {{}expandingloop@a}
      {%
      ifxq@stop#1%
      else
      afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
      fi
      }%
      }%<<<
      newcommandexpandingloop@d[1]%>>>
      {%
      ifcasetestargs{#1}
      afterorfiunexpandedexpandafter{#1}expandingloop@b%
      orafterorfiexpandingloop@d@i{#1}%
      orafterorfiexpandingloop@d@ii{#1}%
      orafterorfiexpandingloop@d@iii{#1}%
      orafterorfiexpandingloop@d@iv{#1}%
      orafterorfiexpandingloop@d@v{#1}%
      orafterorfiexpandingloop@d@vi{#1}%
      orafterorfiexpandingloop@d@vii{#1}%
      orafterorfiexpandingloop@d@viii{#1}%
      orafterfiexpandingloop@d@ix{#1}%
      orDelimitedArgumentError
      fi
      }%<<<
      newcommandexpandingloop@d@group[3]%>>>
      {%
      ifxq@stop#3%
      OutOfArgumentsError
      else
      afterfiexpandingloop@d@group@a{#1}{#2{#3}}%
      fi
      }%<<<
      defexpandingloop@d@group@a#1#2#3#%>>>
      {%
      #1{#2}#3q@stop
      }%<<<
      newcommandexpandingloop@d@exec[1]%>>>
      {%
      unexpandedexpandafter{#1}expandingloop@b
      }%<<<
      newcommandexpandingloop@d@i[2]%>>>
      {%
      ifxq@stop#2%
      afterelsefiexpandingloop@d@group{expandingloop@d@exec}{#1}%
      else
      afterfiexpandingloop@d@exec{#1#2}%
      fi
      }%<<<
      newcommanddef@expandingloop@d@[2]%>>>
      {%
      expandafteredefcsname expandingloop@d@#1endcsname##1##2%
      {%
      unexpanded{ifxq@stop}##2%
      unexpanded{afterelsefiexpandingloop@d@group}%
      expandafternoexpandcsname expandingloop@d@#2endcsname{##1}%
      unexpanded{else
      afterfi}%
      expandafternoexpandcsname expandingloop@d@#2endcsname{##1##2}%
      noexpandfi
      }%
      }%<<<
      def@expandingloop@d@{ix}{viii}
      def@expandingloop@d@{viii}{vii}
      def@expandingloop@d@{vii}{vi}
      def@expandingloop@d@{vi}{v}
      def@expandingloop@d@{v}{iv}
      def@expandingloop@d@{iv}{iii}
      def@expandingloop@d@{iii}{ii}
      def@expandingloop@d@{ii}{i}
      newcommandsingleallexpand[1]%>>>
      {%
      edef#1{expandafterexpandingloop@a#1{q@stop}}%
      }%<<<
      newcommandtestargs[1]%>>>
      {%
      expandaftertestargs@ameaning#1->q@markq@stop%
      }%<<<
      longdeftestargs@a#1->#2#3q@stop%>>>
      {%
      ifxq@mark#2%
      afterelsefi0%
      else
      afterfitestargs@b#1q@stop
      fi
      }%<<<
      longdeftestargs@b#1:#2q@stop%>>>
      {%
      ifempty{#2}
      {0}
      {testargs@c#2q@stop}%
      }%<<<
      begingroup
      catcode`#=12
      defzz{endgroupdefmyhashtag{#}}
      zz
      longedeftestargs@c#1#2#3q@stop%>>>
      {%
      noexpandifxmyhashtag#1%
      noexpandifdigit{#2}
      {%
      noexpandifempty{#3}
      {noexpandafterelsefi#2}
      {noexpandafterelsefinoexpandtestargs@c#3noexpandq@stop}%
      }
      {10}% macros don't take >9 arguments so this is a great error flag
      noexpandelse
      10% macros don't take >9 arguments so this is a great error flag
      noexpandfi
      }%<<<
      makeatother

      newcommandMeaning[1]{texttt{meaning#1}}

      begin{document}
      noindent
      For verb|foo|:

      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp

      noindent
      For verb|c|:

      lettmpc
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      New answer



      The following expands every token in tmp (which is what you want, I hope) in a more reliable way. I didn't test it thoroughly though. It should only work for contents that don't take arguments.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      defa{3}
      defb{2a}
      defc{1{b}}

      defafterfi#1fi{fi#1}
      makeatletter
      defq@stop{q@stop}
      defexpandingloop@a#1#%
      {%
      expandingloop@b#1q@stop
      expandingloop@c
      }
      defexpandingloop@b#1%
      {%
      ifxq@stop#1%
      else
      afterfiunexpandedexpandafter{#1}expandingloop@b
      fi
      }
      newcommandexpandingloop@c[1]
      {%
      ifxq@stop#1%
      else
      afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
      fi
      }
      newcommandsingleallexpand[1]
      {%
      edef#1{expandafterexpandingloop@a#1{q@stop}}%
      }
      makeatother

      newcommandMeaning[1]{texttt{meaning#1}}


      begin{document}
      noindent
      For verb|foo|:

      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp

      noindent
      For verb|c|:

      lettmpc
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      enter image description here





      Old answer



      Both of the following only expand the first token.



      You can use edeffooA{unexpandedexpandafterexpandafterexpandafter{fooB}} to define fooA to be the same as a fooB expanded twice.



      Doing stuff with a temporary macro one could do something like the following.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      newcommandsingleexpand[1]
      {%
      edef#1{unexpandedexpandafterexpandafterexpandafter{#1}}%
      }

      newcommandMeaning[1]{texttt{meaning#1}}


      begin{document}
      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleexpandtmp
      Expanded once:
      Meaningtmp

      singleexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      Being evil when the argument contains a group (but it works in the minimal example, everything else is a matter of adding an infinite number of tests):



      defafterfi#1fi{fi#1}
      defexpandingloop#1#2endexpandingloop
      {%
      unexpandedexpandafter{#1}%
      ifrelaxdetokenize{#2}relax
      else
      afterfiexpandingloop#2endexpandingloop
      fi
      }
      newcommandsingleallexpand[1]
      {%
      edef#1{expandafterexpandingloop#1endexpandingloop}%
      }





      share|improve this answer


























      • Sorry. I really should have explicitly said that it's not only the first expandable token.

        – Andreas Storvik Strauman
        Nov 24 '18 at 21:45














      4












      4








      4







      Newer new answer



      The following expands every expandable token once and if that token needs arguments they are supplied (doesn't work for delimited arguments like with deffoo#1.{#1}). Note that this is not necessarily how TeX would expand things. I created it mostly because I was curious how one could do it.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      defa{3}
      defb{2a}
      makeatletter
      defc{1b 9}
      makeatother

      defafterfi#1fi{fi#1}
      defafterelsefi#1else#2fi{fi#1}
      defafterorfi#1or#2fi{fi#1}
      defafterfiBfi#1#2{fi#2}
      defafterelsefiAelse#1fi#2#3{fi#2}
      makeatletter
      newcommandifempty[1]%>>>
      {%
      ifrelaxdetokenize{#1}relax
      afterelsefiA
      else
      afterfiB
      fi
      }%<<<
      newcommandifdigit[1]%>>>
      {%
      ifx1#1afterelsefiA
      elseifdigit@b2#1%
      elseifdigit@b3#1%
      elseifdigit@b4#1%
      elseifdigit@b5#1%
      elseifdigit@b6#1%
      elseifdigit@b7#1%
      elseifdigit@b8#1%
      elseifdigit@b9#1%
      elseifdigit@b0#1%
      elseafterfiB
      fi
      }%<<<
      newcommandifdigit@b[2]%>>>
      {%
      fiifx#1#2afterelsefiA
      }%<<<
      defq@stop{q@stopError}
      defq@mark{q@markError}
      longdefexpandingloop@a#1#%>>>
      {%
      expandingloop@b#1q@stop
      }%<<<
      longdefexpandingloop@b#1%>>>
      {%
      ifxq@stop#1%
      afterelsefiexpandingloop@c
      else
      afterfiexpandingloop@d#1%
      fi
      }%<<<
      newcommandexpandingloop@c[1]%>>>
      {%
      ifempty{#1}
      {{}expandingloop@a}
      {%
      ifxq@stop#1%
      else
      afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
      fi
      }%
      }%<<<
      newcommandexpandingloop@d[1]%>>>
      {%
      ifcasetestargs{#1}
      afterorfiunexpandedexpandafter{#1}expandingloop@b%
      orafterorfiexpandingloop@d@i{#1}%
      orafterorfiexpandingloop@d@ii{#1}%
      orafterorfiexpandingloop@d@iii{#1}%
      orafterorfiexpandingloop@d@iv{#1}%
      orafterorfiexpandingloop@d@v{#1}%
      orafterorfiexpandingloop@d@vi{#1}%
      orafterorfiexpandingloop@d@vii{#1}%
      orafterorfiexpandingloop@d@viii{#1}%
      orafterfiexpandingloop@d@ix{#1}%
      orDelimitedArgumentError
      fi
      }%<<<
      newcommandexpandingloop@d@group[3]%>>>
      {%
      ifxq@stop#3%
      OutOfArgumentsError
      else
      afterfiexpandingloop@d@group@a{#1}{#2{#3}}%
      fi
      }%<<<
      defexpandingloop@d@group@a#1#2#3#%>>>
      {%
      #1{#2}#3q@stop
      }%<<<
      newcommandexpandingloop@d@exec[1]%>>>
      {%
      unexpandedexpandafter{#1}expandingloop@b
      }%<<<
      newcommandexpandingloop@d@i[2]%>>>
      {%
      ifxq@stop#2%
      afterelsefiexpandingloop@d@group{expandingloop@d@exec}{#1}%
      else
      afterfiexpandingloop@d@exec{#1#2}%
      fi
      }%<<<
      newcommanddef@expandingloop@d@[2]%>>>
      {%
      expandafteredefcsname expandingloop@d@#1endcsname##1##2%
      {%
      unexpanded{ifxq@stop}##2%
      unexpanded{afterelsefiexpandingloop@d@group}%
      expandafternoexpandcsname expandingloop@d@#2endcsname{##1}%
      unexpanded{else
      afterfi}%
      expandafternoexpandcsname expandingloop@d@#2endcsname{##1##2}%
      noexpandfi
      }%
      }%<<<
      def@expandingloop@d@{ix}{viii}
      def@expandingloop@d@{viii}{vii}
      def@expandingloop@d@{vii}{vi}
      def@expandingloop@d@{vi}{v}
      def@expandingloop@d@{v}{iv}
      def@expandingloop@d@{iv}{iii}
      def@expandingloop@d@{iii}{ii}
      def@expandingloop@d@{ii}{i}
      newcommandsingleallexpand[1]%>>>
      {%
      edef#1{expandafterexpandingloop@a#1{q@stop}}%
      }%<<<
      newcommandtestargs[1]%>>>
      {%
      expandaftertestargs@ameaning#1->q@markq@stop%
      }%<<<
      longdeftestargs@a#1->#2#3q@stop%>>>
      {%
      ifxq@mark#2%
      afterelsefi0%
      else
      afterfitestargs@b#1q@stop
      fi
      }%<<<
      longdeftestargs@b#1:#2q@stop%>>>
      {%
      ifempty{#2}
      {0}
      {testargs@c#2q@stop}%
      }%<<<
      begingroup
      catcode`#=12
      defzz{endgroupdefmyhashtag{#}}
      zz
      longedeftestargs@c#1#2#3q@stop%>>>
      {%
      noexpandifxmyhashtag#1%
      noexpandifdigit{#2}
      {%
      noexpandifempty{#3}
      {noexpandafterelsefi#2}
      {noexpandafterelsefinoexpandtestargs@c#3noexpandq@stop}%
      }
      {10}% macros don't take >9 arguments so this is a great error flag
      noexpandelse
      10% macros don't take >9 arguments so this is a great error flag
      noexpandfi
      }%<<<
      makeatother

      newcommandMeaning[1]{texttt{meaning#1}}

      begin{document}
      noindent
      For verb|foo|:

      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp

      noindent
      For verb|c|:

      lettmpc
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      New answer



      The following expands every token in tmp (which is what you want, I hope) in a more reliable way. I didn't test it thoroughly though. It should only work for contents that don't take arguments.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      defa{3}
      defb{2a}
      defc{1{b}}

      defafterfi#1fi{fi#1}
      makeatletter
      defq@stop{q@stop}
      defexpandingloop@a#1#%
      {%
      expandingloop@b#1q@stop
      expandingloop@c
      }
      defexpandingloop@b#1%
      {%
      ifxq@stop#1%
      else
      afterfiunexpandedexpandafter{#1}expandingloop@b
      fi
      }
      newcommandexpandingloop@c[1]
      {%
      ifxq@stop#1%
      else
      afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
      fi
      }
      newcommandsingleallexpand[1]
      {%
      edef#1{expandafterexpandingloop@a#1{q@stop}}%
      }
      makeatother

      newcommandMeaning[1]{texttt{meaning#1}}


      begin{document}
      noindent
      For verb|foo|:

      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp

      noindent
      For verb|c|:

      lettmpc
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      enter image description here





      Old answer



      Both of the following only expand the first token.



      You can use edeffooA{unexpandedexpandafterexpandafterexpandafter{fooB}} to define fooA to be the same as a fooB expanded twice.



      Doing stuff with a temporary macro one could do something like the following.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      newcommandsingleexpand[1]
      {%
      edef#1{unexpandedexpandafterexpandafterexpandafter{#1}}%
      }

      newcommandMeaning[1]{texttt{meaning#1}}


      begin{document}
      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleexpandtmp
      Expanded once:
      Meaningtmp

      singleexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      Being evil when the argument contains a group (but it works in the minimal example, everything else is a matter of adding an infinite number of tests):



      defafterfi#1fi{fi#1}
      defexpandingloop#1#2endexpandingloop
      {%
      unexpandedexpandafter{#1}%
      ifrelaxdetokenize{#2}relax
      else
      afterfiexpandingloop#2endexpandingloop
      fi
      }
      newcommandsingleallexpand[1]
      {%
      edef#1{expandafterexpandingloop#1endexpandingloop}%
      }





      share|improve this answer















      Newer new answer



      The following expands every expandable token once and if that token needs arguments they are supplied (doesn't work for delimited arguments like with deffoo#1.{#1}). Note that this is not necessarily how TeX would expand things. I created it mostly because I was curious how one could do it.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      defa{3}
      defb{2a}
      makeatletter
      defc{1b 9}
      makeatother

      defafterfi#1fi{fi#1}
      defafterelsefi#1else#2fi{fi#1}
      defafterorfi#1or#2fi{fi#1}
      defafterfiBfi#1#2{fi#2}
      defafterelsefiAelse#1fi#2#3{fi#2}
      makeatletter
      newcommandifempty[1]%>>>
      {%
      ifrelaxdetokenize{#1}relax
      afterelsefiA
      else
      afterfiB
      fi
      }%<<<
      newcommandifdigit[1]%>>>
      {%
      ifx1#1afterelsefiA
      elseifdigit@b2#1%
      elseifdigit@b3#1%
      elseifdigit@b4#1%
      elseifdigit@b5#1%
      elseifdigit@b6#1%
      elseifdigit@b7#1%
      elseifdigit@b8#1%
      elseifdigit@b9#1%
      elseifdigit@b0#1%
      elseafterfiB
      fi
      }%<<<
      newcommandifdigit@b[2]%>>>
      {%
      fiifx#1#2afterelsefiA
      }%<<<
      defq@stop{q@stopError}
      defq@mark{q@markError}
      longdefexpandingloop@a#1#%>>>
      {%
      expandingloop@b#1q@stop
      }%<<<
      longdefexpandingloop@b#1%>>>
      {%
      ifxq@stop#1%
      afterelsefiexpandingloop@c
      else
      afterfiexpandingloop@d#1%
      fi
      }%<<<
      newcommandexpandingloop@c[1]%>>>
      {%
      ifempty{#1}
      {{}expandingloop@a}
      {%
      ifxq@stop#1%
      else
      afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
      fi
      }%
      }%<<<
      newcommandexpandingloop@d[1]%>>>
      {%
      ifcasetestargs{#1}
      afterorfiunexpandedexpandafter{#1}expandingloop@b%
      orafterorfiexpandingloop@d@i{#1}%
      orafterorfiexpandingloop@d@ii{#1}%
      orafterorfiexpandingloop@d@iii{#1}%
      orafterorfiexpandingloop@d@iv{#1}%
      orafterorfiexpandingloop@d@v{#1}%
      orafterorfiexpandingloop@d@vi{#1}%
      orafterorfiexpandingloop@d@vii{#1}%
      orafterorfiexpandingloop@d@viii{#1}%
      orafterfiexpandingloop@d@ix{#1}%
      orDelimitedArgumentError
      fi
      }%<<<
      newcommandexpandingloop@d@group[3]%>>>
      {%
      ifxq@stop#3%
      OutOfArgumentsError
      else
      afterfiexpandingloop@d@group@a{#1}{#2{#3}}%
      fi
      }%<<<
      defexpandingloop@d@group@a#1#2#3#%>>>
      {%
      #1{#2}#3q@stop
      }%<<<
      newcommandexpandingloop@d@exec[1]%>>>
      {%
      unexpandedexpandafter{#1}expandingloop@b
      }%<<<
      newcommandexpandingloop@d@i[2]%>>>
      {%
      ifxq@stop#2%
      afterelsefiexpandingloop@d@group{expandingloop@d@exec}{#1}%
      else
      afterfiexpandingloop@d@exec{#1#2}%
      fi
      }%<<<
      newcommanddef@expandingloop@d@[2]%>>>
      {%
      expandafteredefcsname expandingloop@d@#1endcsname##1##2%
      {%
      unexpanded{ifxq@stop}##2%
      unexpanded{afterelsefiexpandingloop@d@group}%
      expandafternoexpandcsname expandingloop@d@#2endcsname{##1}%
      unexpanded{else
      afterfi}%
      expandafternoexpandcsname expandingloop@d@#2endcsname{##1##2}%
      noexpandfi
      }%
      }%<<<
      def@expandingloop@d@{ix}{viii}
      def@expandingloop@d@{viii}{vii}
      def@expandingloop@d@{vii}{vi}
      def@expandingloop@d@{vi}{v}
      def@expandingloop@d@{v}{iv}
      def@expandingloop@d@{iv}{iii}
      def@expandingloop@d@{iii}{ii}
      def@expandingloop@d@{ii}{i}
      newcommandsingleallexpand[1]%>>>
      {%
      edef#1{expandafterexpandingloop@a#1{q@stop}}%
      }%<<<
      newcommandtestargs[1]%>>>
      {%
      expandaftertestargs@ameaning#1->q@markq@stop%
      }%<<<
      longdeftestargs@a#1->#2#3q@stop%>>>
      {%
      ifxq@mark#2%
      afterelsefi0%
      else
      afterfitestargs@b#1q@stop
      fi
      }%<<<
      longdeftestargs@b#1:#2q@stop%>>>
      {%
      ifempty{#2}
      {0}
      {testargs@c#2q@stop}%
      }%<<<
      begingroup
      catcode`#=12
      defzz{endgroupdefmyhashtag{#}}
      zz
      longedeftestargs@c#1#2#3q@stop%>>>
      {%
      noexpandifxmyhashtag#1%
      noexpandifdigit{#2}
      {%
      noexpandifempty{#3}
      {noexpandafterelsefi#2}
      {noexpandafterelsefinoexpandtestargs@c#3noexpandq@stop}%
      }
      {10}% macros don't take >9 arguments so this is a great error flag
      noexpandelse
      10% macros don't take >9 arguments so this is a great error flag
      noexpandfi
      }%<<<
      makeatother

      newcommandMeaning[1]{texttt{meaning#1}}

      begin{document}
      noindent
      For verb|foo|:

      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp

      noindent
      For verb|c|:

      lettmpc
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      New answer



      The following expands every token in tmp (which is what you want, I hope) in a more reliable way. I didn't test it thoroughly though. It should only work for contents that don't take arguments.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      defa{3}
      defb{2a}
      defc{1{b}}

      defafterfi#1fi{fi#1}
      makeatletter
      defq@stop{q@stop}
      defexpandingloop@a#1#%
      {%
      expandingloop@b#1q@stop
      expandingloop@c
      }
      defexpandingloop@b#1%
      {%
      ifxq@stop#1%
      else
      afterfiunexpandedexpandafter{#1}expandingloop@b
      fi
      }
      newcommandexpandingloop@c[1]
      {%
      ifxq@stop#1%
      else
      afterfi{expandingloop@a#1{q@stop}}expandingloop@a%
      fi
      }
      newcommandsingleallexpand[1]
      {%
      edef#1{expandafterexpandingloop@a#1{q@stop}}%
      }
      makeatother

      newcommandMeaning[1]{texttt{meaning#1}}


      begin{document}
      noindent
      For verb|foo|:

      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp

      noindent
      For verb|c|:

      lettmpc
      Unexpanded:
      Meaningtmp

      singleallexpandtmp
      Expanded once:
      Meaningtmp

      singleallexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      enter image description here





      Old answer



      Both of the following only expand the first token.



      You can use edeffooA{unexpandedexpandafterexpandafterexpandafter{fooB}} to define fooA to be the same as a fooB expanded twice.



      Doing stuff with a temporary macro one could do something like the following.



      documentclass{article}

      newcommandfoo{bazA}
      newcommandbazA{bazB}
      newcommandbazB{bar}

      newcommandsingleexpand[1]
      {%
      edef#1{unexpandedexpandafterexpandafterexpandafter{#1}}%
      }

      newcommandMeaning[1]{texttt{meaning#1}}


      begin{document}
      lettmpfoo
      Unexpanded:
      Meaningtmp

      singleexpandtmp
      Expanded once:
      Meaningtmp

      singleexpandtmp
      Expanded twice:
      Meaningtmp
      end{document}


      Being evil when the argument contains a group (but it works in the minimal example, everything else is a matter of adding an infinite number of tests):



      defafterfi#1fi{fi#1}
      defexpandingloop#1#2endexpandingloop
      {%
      unexpandedexpandafter{#1}%
      ifrelaxdetokenize{#2}relax
      else
      afterfiexpandingloop#2endexpandingloop
      fi
      }
      newcommandsingleallexpand[1]
      {%
      edef#1{expandafterexpandingloop#1endexpandingloop}%
      }






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Nov 26 '18 at 0:42

























      answered Nov 24 '18 at 21:38









      SkillmonSkillmon

      21.8k11942




      21.8k11942













      • Sorry. I really should have explicitly said that it's not only the first expandable token.

        – Andreas Storvik Strauman
        Nov 24 '18 at 21:45



















      • Sorry. I really should have explicitly said that it's not only the first expandable token.

        – Andreas Storvik Strauman
        Nov 24 '18 at 21:45

















      Sorry. I really should have explicitly said that it's not only the first expandable token.

      – Andreas Storvik Strauman
      Nov 24 '18 at 21:45





      Sorry. I really should have explicitly said that it's not only the first expandable token.

      – Andreas Storvik Strauman
      Nov 24 '18 at 21:45











      5














      I get



      > zz=macro:
      ->12a 12a .


      on the terminal from etex (or pdftex) from



      defa{3}
      defb{2a}
      defc{1b1b}
      defafterfi#1fi{fi#1}
      deffoo#1{ifxrelax#1elseafterfiexpandafterunexpandedexpandafter{#1}foofi}
      edefzz{expandafterfoocrelax}

      showzz

      bye




      Note that this is the expansion order that you asked for, as far as I can tell but is not the order that TeX would use normally so it isnt really "expanding twice"



      Consider



      defa{b} defb#1{}  defc{zzzzz}
      defz{ac}


      by your definition I think you want to expand a and c once in the first step so getting a "first expansion" of z as b zzzzz then on a second step expand b so get zzzz.



      However TeX would fully expand the first token at each stage, so in the first step get bc then in the second step get an empty list. c would never be expanded at all by TeX.






      share|improve this answer






























        5














        I get



        > zz=macro:
        ->12a 12a .


        on the terminal from etex (or pdftex) from



        defa{3}
        defb{2a}
        defc{1b1b}
        defafterfi#1fi{fi#1}
        deffoo#1{ifxrelax#1elseafterfiexpandafterunexpandedexpandafter{#1}foofi}
        edefzz{expandafterfoocrelax}

        showzz

        bye




        Note that this is the expansion order that you asked for, as far as I can tell but is not the order that TeX would use normally so it isnt really "expanding twice"



        Consider



        defa{b} defb#1{}  defc{zzzzz}
        defz{ac}


        by your definition I think you want to expand a and c once in the first step so getting a "first expansion" of z as b zzzzz then on a second step expand b so get zzzz.



        However TeX would fully expand the first token at each stage, so in the first step get bc then in the second step get an empty list. c would never be expanded at all by TeX.






        share|improve this answer




























          5












          5








          5







          I get



          > zz=macro:
          ->12a 12a .


          on the terminal from etex (or pdftex) from



          defa{3}
          defb{2a}
          defc{1b1b}
          defafterfi#1fi{fi#1}
          deffoo#1{ifxrelax#1elseafterfiexpandafterunexpandedexpandafter{#1}foofi}
          edefzz{expandafterfoocrelax}

          showzz

          bye




          Note that this is the expansion order that you asked for, as far as I can tell but is not the order that TeX would use normally so it isnt really "expanding twice"



          Consider



          defa{b} defb#1{}  defc{zzzzz}
          defz{ac}


          by your definition I think you want to expand a and c once in the first step so getting a "first expansion" of z as b zzzzz then on a second step expand b so get zzzz.



          However TeX would fully expand the first token at each stage, so in the first step get bc then in the second step get an empty list. c would never be expanded at all by TeX.






          share|improve this answer















          I get



          > zz=macro:
          ->12a 12a .


          on the terminal from etex (or pdftex) from



          defa{3}
          defb{2a}
          defc{1b1b}
          defafterfi#1fi{fi#1}
          deffoo#1{ifxrelax#1elseafterfiexpandafterunexpandedexpandafter{#1}foofi}
          edefzz{expandafterfoocrelax}

          showzz

          bye




          Note that this is the expansion order that you asked for, as far as I can tell but is not the order that TeX would use normally so it isnt really "expanding twice"



          Consider



          defa{b} defb#1{}  defc{zzzzz}
          defz{ac}


          by your definition I think you want to expand a and c once in the first step so getting a "first expansion" of z as b zzzzz then on a second step expand b so get zzzz.



          However TeX would fully expand the first token at each stage, so in the first step get bc then in the second step get an empty list. c would never be expanded at all by TeX.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 24 '18 at 22:03

























          answered Nov 24 '18 at 21:48









          David CarlisleDavid Carlisle

          486k4111231867




          486k4111231867























              1














              I think a reliable algorithm for expanding outgoing from an arbitrary set of tokens at most k times is not possible:



              Expanding at most one time is already a problem:



              You'd need an algorithm which recursively iterates on a &langle;list of not yet expanded tokens&rangle; and maintains a &langle;list of already expanded tokens&rangle; as follows:





              Step 1:



              Check whether the &langle;list of not yet expanded tokens&rangle; is empty.



              If so: Deliver the &langle;list of already expanded tokens&rangle;.



              If not so:





              • In case the first element/the first token of the &langle;list of
                not yet expanded tokens&rangle;
                is not expandable, remove it from
                the &langle;list of not yet expanded tokens&rangle; and add it
                at the end of the &langle;list of already expanded
                tokens&rangle;
                .



                In case the first element/the first token of the
                &langle;list of not yet expanded tokens&rangle; is expandable,
                expand it and remove the result of that expansion from the
                &langle;list of not yet expanded tokens&rangle; and add the
                result of that expansion at the end of the &langle;list of already
                expanded tokens&rangle;



              • Repeat Step 1.




              One crucial point hereby is "removing the result of that expansion from the &langle;list of not yet expanded tokens&rangle; and adding the result of that expansion at the end of the &langle;list of already expanded tokens&rangle;".



              That point is crucial because it implies that after expansion you need to detect which tokens belong to the result of that expansion and which tokens were already in the &langle;list of not yet expanded tokens&rangle; before that expansion took place.



              Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}

              , while the &langle;list of not yet expanded tokens&rangle; holds the following content:
              macro ABC Whatsoever



              Now you need to have macro expanded once. After that, the &langle;list of not yet expanded tokens&rangle; holds the following content:
              ABC Whatsoever.



              Now you need to move the result from expanding macro towards the &langle;list of already expanded tokens&rangle;.



              In this case the result of expanding macro is formed by the tokens ABC.



              How to detect that these ABC are the replacement-text/the expansion-result from expanding macro and thus are not the same as the ABC that before expansion were in the &langle;list of not yet expanded tokens&rangle;?



              (Parsing the result of meaning with every expandable token for finding out whether it is a macro that processes arguments does not deliver reliable information about the parameter-texts of macros because with meaning you don't have reliable information about the category-codes of tokens / about whether a set of delivered characters denotes a set of character tokens (of whatsoever category code) or a control sequence...)



              Another crucial point is that you'd need to iterate "token-wise" while macros usually work "argument-wise".





              In your special case, where you already know about definitions and tokens delivered by expansion, you can, e.g., do:



              defa{3}
              defb{2a}
              defc{1b}
              % You wish to obtain a macro containing "12a" from using only c


              % expandaf-% expandaf-%
              % ter- % ter- %
              % chain 1 % chain 2 %
              % | % | %
              expandafterexpandafter
              expandafter def
              expandafterexpandafter
              expandafter expandedTwice
              expandafterexpandafter
              expandafter {%
              expandafterexpandafter
              c}


              expandafter-chain 1 delivers:



              % expandaf-%
              % ter- %
              % chain 2 %
              % | %
              expandafter
              def
              expandafter
              expandedTwice
              expandafter
              {%
              expandafter
              1b}


              expandafter-chain 2 delivers:



              def
              expandedTwice
              {%
              12a}


              (In case you are not familiar to expandafter:



              expandafter is an expandable primitive which works on the next and on the next but one token:



              In case the next but one token is expandable, the replacement-text of
              expandafter&langle;next token&rangle;&langle;next but one token&rangle;

              will be
              &langle;next token&rangle;&langle;top-level-expansion of next but one token&rangle;.



              In case the next but one token is not expandable, the replacement-text of
              expandafter&langle;next token&rangle;&langle;next but one token&rangle;

              will be
              &langle;next token&rangle;&langle;next but one token&rangle;.



              In other words: (La)TeX considers the expandafter-work done and removes the expandafter from the token-stream when top-level-expanding the next-but-one token is finished.

              That's why you can have expandafter-chains for "hopping" over tokens that shall not be expanded.



              E.g., if you have deffoo{bar}, and do
              expandafter 1expandafter 2expandafter 3foo

              , you will get
              123bar:



              Carrying out the first expandafter causes the second expandafter to be carried out. Hereby "carrying out the second expandafter" is considered an aspect of carrying out the first expandafter.

              Carrying out the second expandafter in turn causes the third expandafter to be carried out. Hereby "carrying out the third expandafter" is considered an aspect of carrying out the second expandafter.
              The third expandafter causes foo to be top-level-expanded.

              When the top-level-expansion of foo is delivered, (La)TeX will consider the expansion-work of the third expandafter done.

              This expansion-work was initiated by the second expndafter.
              As the expansion-work initiated by the second expandafter is done, now the expansion-work of the second expandafter is done.
              The expansion-work of the second expandafter was initiated by the first expandafter.

              As the expansion-work initiated by the first expandafter is done, now the expansion-work of the first expandafter is done.)





              But if you have, e.g.,



              catcode`(=1 %
              catcode`)=2 %
              defa{3}
              defb{2a}
              defc{11111(1)11111b}


              , and wish to obtain 11111(1)111112a—parentheses still of catcode 1 / 2 —outgoing from c, this will probably turn out an interesting task.





              By the way 1: The methods of choice for obtaining the result of expansion highly depend on the context:



              Within a "pure expansion context", i.e., e.g., within csname..endcsname or within write{...} or within edef{..} you cannot have LaTeX define temporary macros/you cannot have LaTeX perform whatsoever assignments (with the exception of the result of csname..endcsname locally assigning the meaning of the relax-primitive in case the control-sequence-token constructed is undefined).



              By the way 2: edef/ xdef is not reliable in all situations.

              E.g., look at:



              edeftest{%
              Where does the assignment end? Here? iffalse{fi}%
              {iffalse}fi Or here?%
              }%
              par
              meaningtest





              share|improve this answer






























                1














                I think a reliable algorithm for expanding outgoing from an arbitrary set of tokens at most k times is not possible:



                Expanding at most one time is already a problem:



                You'd need an algorithm which recursively iterates on a &langle;list of not yet expanded tokens&rangle; and maintains a &langle;list of already expanded tokens&rangle; as follows:





                Step 1:



                Check whether the &langle;list of not yet expanded tokens&rangle; is empty.



                If so: Deliver the &langle;list of already expanded tokens&rangle;.



                If not so:





                • In case the first element/the first token of the &langle;list of
                  not yet expanded tokens&rangle;
                  is not expandable, remove it from
                  the &langle;list of not yet expanded tokens&rangle; and add it
                  at the end of the &langle;list of already expanded
                  tokens&rangle;
                  .



                  In case the first element/the first token of the
                  &langle;list of not yet expanded tokens&rangle; is expandable,
                  expand it and remove the result of that expansion from the
                  &langle;list of not yet expanded tokens&rangle; and add the
                  result of that expansion at the end of the &langle;list of already
                  expanded tokens&rangle;



                • Repeat Step 1.




                One crucial point hereby is "removing the result of that expansion from the &langle;list of not yet expanded tokens&rangle; and adding the result of that expansion at the end of the &langle;list of already expanded tokens&rangle;".



                That point is crucial because it implies that after expansion you need to detect which tokens belong to the result of that expansion and which tokens were already in the &langle;list of not yet expanded tokens&rangle; before that expansion took place.



                Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}

                , while the &langle;list of not yet expanded tokens&rangle; holds the following content:
                macro ABC Whatsoever



                Now you need to have macro expanded once. After that, the &langle;list of not yet expanded tokens&rangle; holds the following content:
                ABC Whatsoever.



                Now you need to move the result from expanding macro towards the &langle;list of already expanded tokens&rangle;.



                In this case the result of expanding macro is formed by the tokens ABC.



                How to detect that these ABC are the replacement-text/the expansion-result from expanding macro and thus are not the same as the ABC that before expansion were in the &langle;list of not yet expanded tokens&rangle;?



                (Parsing the result of meaning with every expandable token for finding out whether it is a macro that processes arguments does not deliver reliable information about the parameter-texts of macros because with meaning you don't have reliable information about the category-codes of tokens / about whether a set of delivered characters denotes a set of character tokens (of whatsoever category code) or a control sequence...)



                Another crucial point is that you'd need to iterate "token-wise" while macros usually work "argument-wise".





                In your special case, where you already know about definitions and tokens delivered by expansion, you can, e.g., do:



                defa{3}
                defb{2a}
                defc{1b}
                % You wish to obtain a macro containing "12a" from using only c


                % expandaf-% expandaf-%
                % ter- % ter- %
                % chain 1 % chain 2 %
                % | % | %
                expandafterexpandafter
                expandafter def
                expandafterexpandafter
                expandafter expandedTwice
                expandafterexpandafter
                expandafter {%
                expandafterexpandafter
                c}


                expandafter-chain 1 delivers:



                % expandaf-%
                % ter- %
                % chain 2 %
                % | %
                expandafter
                def
                expandafter
                expandedTwice
                expandafter
                {%
                expandafter
                1b}


                expandafter-chain 2 delivers:



                def
                expandedTwice
                {%
                12a}


                (In case you are not familiar to expandafter:



                expandafter is an expandable primitive which works on the next and on the next but one token:



                In case the next but one token is expandable, the replacement-text of
                expandafter&langle;next token&rangle;&langle;next but one token&rangle;

                will be
                &langle;next token&rangle;&langle;top-level-expansion of next but one token&rangle;.



                In case the next but one token is not expandable, the replacement-text of
                expandafter&langle;next token&rangle;&langle;next but one token&rangle;

                will be
                &langle;next token&rangle;&langle;next but one token&rangle;.



                In other words: (La)TeX considers the expandafter-work done and removes the expandafter from the token-stream when top-level-expanding the next-but-one token is finished.

                That's why you can have expandafter-chains for "hopping" over tokens that shall not be expanded.



                E.g., if you have deffoo{bar}, and do
                expandafter 1expandafter 2expandafter 3foo

                , you will get
                123bar:



                Carrying out the first expandafter causes the second expandafter to be carried out. Hereby "carrying out the second expandafter" is considered an aspect of carrying out the first expandafter.

                Carrying out the second expandafter in turn causes the third expandafter to be carried out. Hereby "carrying out the third expandafter" is considered an aspect of carrying out the second expandafter.
                The third expandafter causes foo to be top-level-expanded.

                When the top-level-expansion of foo is delivered, (La)TeX will consider the expansion-work of the third expandafter done.

                This expansion-work was initiated by the second expndafter.
                As the expansion-work initiated by the second expandafter is done, now the expansion-work of the second expandafter is done.
                The expansion-work of the second expandafter was initiated by the first expandafter.

                As the expansion-work initiated by the first expandafter is done, now the expansion-work of the first expandafter is done.)





                But if you have, e.g.,



                catcode`(=1 %
                catcode`)=2 %
                defa{3}
                defb{2a}
                defc{11111(1)11111b}


                , and wish to obtain 11111(1)111112a—parentheses still of catcode 1 / 2 —outgoing from c, this will probably turn out an interesting task.





                By the way 1: The methods of choice for obtaining the result of expansion highly depend on the context:



                Within a "pure expansion context", i.e., e.g., within csname..endcsname or within write{...} or within edef{..} you cannot have LaTeX define temporary macros/you cannot have LaTeX perform whatsoever assignments (with the exception of the result of csname..endcsname locally assigning the meaning of the relax-primitive in case the control-sequence-token constructed is undefined).



                By the way 2: edef/ xdef is not reliable in all situations.

                E.g., look at:



                edeftest{%
                Where does the assignment end? Here? iffalse{fi}%
                {iffalse}fi Or here?%
                }%
                par
                meaningtest





                share|improve this answer




























                  1












                  1








                  1







                  I think a reliable algorithm for expanding outgoing from an arbitrary set of tokens at most k times is not possible:



                  Expanding at most one time is already a problem:



                  You'd need an algorithm which recursively iterates on a &langle;list of not yet expanded tokens&rangle; and maintains a &langle;list of already expanded tokens&rangle; as follows:





                  Step 1:



                  Check whether the &langle;list of not yet expanded tokens&rangle; is empty.



                  If so: Deliver the &langle;list of already expanded tokens&rangle;.



                  If not so:





                  • In case the first element/the first token of the &langle;list of
                    not yet expanded tokens&rangle;
                    is not expandable, remove it from
                    the &langle;list of not yet expanded tokens&rangle; and add it
                    at the end of the &langle;list of already expanded
                    tokens&rangle;
                    .



                    In case the first element/the first token of the
                    &langle;list of not yet expanded tokens&rangle; is expandable,
                    expand it and remove the result of that expansion from the
                    &langle;list of not yet expanded tokens&rangle; and add the
                    result of that expansion at the end of the &langle;list of already
                    expanded tokens&rangle;



                  • Repeat Step 1.




                  One crucial point hereby is "removing the result of that expansion from the &langle;list of not yet expanded tokens&rangle; and adding the result of that expansion at the end of the &langle;list of already expanded tokens&rangle;".



                  That point is crucial because it implies that after expansion you need to detect which tokens belong to the result of that expansion and which tokens were already in the &langle;list of not yet expanded tokens&rangle; before that expansion took place.



                  Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}

                  , while the &langle;list of not yet expanded tokens&rangle; holds the following content:
                  macro ABC Whatsoever



                  Now you need to have macro expanded once. After that, the &langle;list of not yet expanded tokens&rangle; holds the following content:
                  ABC Whatsoever.



                  Now you need to move the result from expanding macro towards the &langle;list of already expanded tokens&rangle;.



                  In this case the result of expanding macro is formed by the tokens ABC.



                  How to detect that these ABC are the replacement-text/the expansion-result from expanding macro and thus are not the same as the ABC that before expansion were in the &langle;list of not yet expanded tokens&rangle;?



                  (Parsing the result of meaning with every expandable token for finding out whether it is a macro that processes arguments does not deliver reliable information about the parameter-texts of macros because with meaning you don't have reliable information about the category-codes of tokens / about whether a set of delivered characters denotes a set of character tokens (of whatsoever category code) or a control sequence...)



                  Another crucial point is that you'd need to iterate "token-wise" while macros usually work "argument-wise".





                  In your special case, where you already know about definitions and tokens delivered by expansion, you can, e.g., do:



                  defa{3}
                  defb{2a}
                  defc{1b}
                  % You wish to obtain a macro containing "12a" from using only c


                  % expandaf-% expandaf-%
                  % ter- % ter- %
                  % chain 1 % chain 2 %
                  % | % | %
                  expandafterexpandafter
                  expandafter def
                  expandafterexpandafter
                  expandafter expandedTwice
                  expandafterexpandafter
                  expandafter {%
                  expandafterexpandafter
                  c}


                  expandafter-chain 1 delivers:



                  % expandaf-%
                  % ter- %
                  % chain 2 %
                  % | %
                  expandafter
                  def
                  expandafter
                  expandedTwice
                  expandafter
                  {%
                  expandafter
                  1b}


                  expandafter-chain 2 delivers:



                  def
                  expandedTwice
                  {%
                  12a}


                  (In case you are not familiar to expandafter:



                  expandafter is an expandable primitive which works on the next and on the next but one token:



                  In case the next but one token is expandable, the replacement-text of
                  expandafter&langle;next token&rangle;&langle;next but one token&rangle;

                  will be
                  &langle;next token&rangle;&langle;top-level-expansion of next but one token&rangle;.



                  In case the next but one token is not expandable, the replacement-text of
                  expandafter&langle;next token&rangle;&langle;next but one token&rangle;

                  will be
                  &langle;next token&rangle;&langle;next but one token&rangle;.



                  In other words: (La)TeX considers the expandafter-work done and removes the expandafter from the token-stream when top-level-expanding the next-but-one token is finished.

                  That's why you can have expandafter-chains for "hopping" over tokens that shall not be expanded.



                  E.g., if you have deffoo{bar}, and do
                  expandafter 1expandafter 2expandafter 3foo

                  , you will get
                  123bar:



                  Carrying out the first expandafter causes the second expandafter to be carried out. Hereby "carrying out the second expandafter" is considered an aspect of carrying out the first expandafter.

                  Carrying out the second expandafter in turn causes the third expandafter to be carried out. Hereby "carrying out the third expandafter" is considered an aspect of carrying out the second expandafter.
                  The third expandafter causes foo to be top-level-expanded.

                  When the top-level-expansion of foo is delivered, (La)TeX will consider the expansion-work of the third expandafter done.

                  This expansion-work was initiated by the second expndafter.
                  As the expansion-work initiated by the second expandafter is done, now the expansion-work of the second expandafter is done.
                  The expansion-work of the second expandafter was initiated by the first expandafter.

                  As the expansion-work initiated by the first expandafter is done, now the expansion-work of the first expandafter is done.)





                  But if you have, e.g.,



                  catcode`(=1 %
                  catcode`)=2 %
                  defa{3}
                  defb{2a}
                  defc{11111(1)11111b}


                  , and wish to obtain 11111(1)111112a—parentheses still of catcode 1 / 2 —outgoing from c, this will probably turn out an interesting task.





                  By the way 1: The methods of choice for obtaining the result of expansion highly depend on the context:



                  Within a "pure expansion context", i.e., e.g., within csname..endcsname or within write{...} or within edef{..} you cannot have LaTeX define temporary macros/you cannot have LaTeX perform whatsoever assignments (with the exception of the result of csname..endcsname locally assigning the meaning of the relax-primitive in case the control-sequence-token constructed is undefined).



                  By the way 2: edef/ xdef is not reliable in all situations.

                  E.g., look at:



                  edeftest{%
                  Where does the assignment end? Here? iffalse{fi}%
                  {iffalse}fi Or here?%
                  }%
                  par
                  meaningtest





                  share|improve this answer















                  I think a reliable algorithm for expanding outgoing from an arbitrary set of tokens at most k times is not possible:



                  Expanding at most one time is already a problem:



                  You'd need an algorithm which recursively iterates on a &langle;list of not yet expanded tokens&rangle; and maintains a &langle;list of already expanded tokens&rangle; as follows:





                  Step 1:



                  Check whether the &langle;list of not yet expanded tokens&rangle; is empty.



                  If so: Deliver the &langle;list of already expanded tokens&rangle;.



                  If not so:





                  • In case the first element/the first token of the &langle;list of
                    not yet expanded tokens&rangle;
                    is not expandable, remove it from
                    the &langle;list of not yet expanded tokens&rangle; and add it
                    at the end of the &langle;list of already expanded
                    tokens&rangle;
                    .



                    In case the first element/the first token of the
                    &langle;list of not yet expanded tokens&rangle; is expandable,
                    expand it and remove the result of that expansion from the
                    &langle;list of not yet expanded tokens&rangle; and add the
                    result of that expansion at the end of the &langle;list of already
                    expanded tokens&rangle;



                  • Repeat Step 1.




                  One crucial point hereby is "removing the result of that expansion from the &langle;list of not yet expanded tokens&rangle; and adding the result of that expansion at the end of the &langle;list of already expanded tokens&rangle;".



                  That point is crucial because it implies that after expansion you need to detect which tokens belong to the result of that expansion and which tokens were already in the &langle;list of not yet expanded tokens&rangle; before that expansion took place.



                  Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}

                  , while the &langle;list of not yet expanded tokens&rangle; holds the following content:
                  macro ABC Whatsoever



                  Now you need to have macro expanded once. After that, the &langle;list of not yet expanded tokens&rangle; holds the following content:
                  ABC Whatsoever.



                  Now you need to move the result from expanding macro towards the &langle;list of already expanded tokens&rangle;.



                  In this case the result of expanding macro is formed by the tokens ABC.



                  How to detect that these ABC are the replacement-text/the expansion-result from expanding macro and thus are not the same as the ABC that before expansion were in the &langle;list of not yet expanded tokens&rangle;?



                  (Parsing the result of meaning with every expandable token for finding out whether it is a macro that processes arguments does not deliver reliable information about the parameter-texts of macros because with meaning you don't have reliable information about the category-codes of tokens / about whether a set of delivered characters denotes a set of character tokens (of whatsoever category code) or a control sequence...)



                  Another crucial point is that you'd need to iterate "token-wise" while macros usually work "argument-wise".





                  In your special case, where you already know about definitions and tokens delivered by expansion, you can, e.g., do:



                  defa{3}
                  defb{2a}
                  defc{1b}
                  % You wish to obtain a macro containing "12a" from using only c


                  % expandaf-% expandaf-%
                  % ter- % ter- %
                  % chain 1 % chain 2 %
                  % | % | %
                  expandafterexpandafter
                  expandafter def
                  expandafterexpandafter
                  expandafter expandedTwice
                  expandafterexpandafter
                  expandafter {%
                  expandafterexpandafter
                  c}


                  expandafter-chain 1 delivers:



                  % expandaf-%
                  % ter- %
                  % chain 2 %
                  % | %
                  expandafter
                  def
                  expandafter
                  expandedTwice
                  expandafter
                  {%
                  expandafter
                  1b}


                  expandafter-chain 2 delivers:



                  def
                  expandedTwice
                  {%
                  12a}


                  (In case you are not familiar to expandafter:



                  expandafter is an expandable primitive which works on the next and on the next but one token:



                  In case the next but one token is expandable, the replacement-text of
                  expandafter&langle;next token&rangle;&langle;next but one token&rangle;

                  will be
                  &langle;next token&rangle;&langle;top-level-expansion of next but one token&rangle;.



                  In case the next but one token is not expandable, the replacement-text of
                  expandafter&langle;next token&rangle;&langle;next but one token&rangle;

                  will be
                  &langle;next token&rangle;&langle;next but one token&rangle;.



                  In other words: (La)TeX considers the expandafter-work done and removes the expandafter from the token-stream when top-level-expanding the next-but-one token is finished.

                  That's why you can have expandafter-chains for "hopping" over tokens that shall not be expanded.



                  E.g., if you have deffoo{bar}, and do
                  expandafter 1expandafter 2expandafter 3foo

                  , you will get
                  123bar:



                  Carrying out the first expandafter causes the second expandafter to be carried out. Hereby "carrying out the second expandafter" is considered an aspect of carrying out the first expandafter.

                  Carrying out the second expandafter in turn causes the third expandafter to be carried out. Hereby "carrying out the third expandafter" is considered an aspect of carrying out the second expandafter.
                  The third expandafter causes foo to be top-level-expanded.

                  When the top-level-expansion of foo is delivered, (La)TeX will consider the expansion-work of the third expandafter done.

                  This expansion-work was initiated by the second expndafter.
                  As the expansion-work initiated by the second expandafter is done, now the expansion-work of the second expandafter is done.
                  The expansion-work of the second expandafter was initiated by the first expandafter.

                  As the expansion-work initiated by the first expandafter is done, now the expansion-work of the first expandafter is done.)





                  But if you have, e.g.,



                  catcode`(=1 %
                  catcode`)=2 %
                  defa{3}
                  defb{2a}
                  defc{11111(1)11111b}


                  , and wish to obtain 11111(1)111112a—parentheses still of catcode 1 / 2 —outgoing from c, this will probably turn out an interesting task.





                  By the way 1: The methods of choice for obtaining the result of expansion highly depend on the context:



                  Within a "pure expansion context", i.e., e.g., within csname..endcsname or within write{...} or within edef{..} you cannot have LaTeX define temporary macros/you cannot have LaTeX perform whatsoever assignments (with the exception of the result of csname..endcsname locally assigning the meaning of the relax-primitive in case the control-sequence-token constructed is undefined).



                  By the way 2: edef/ xdef is not reliable in all situations.

                  E.g., look at:



                  edeftest{%
                  Where does the assignment end? Here? iffalse{fi}%
                  {iffalse}fi Or here?%
                  }%
                  par
                  meaningtest






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 27 '18 at 19:51

























                  answered Nov 25 '18 at 10:00









                  Ulrich DiezUlrich Diez

                  4,295615




                  4,295615























                      0














                      I'm fairly certain that the following will do expansion of the macros as described in the original question: (In hindsight, using semicolon as termination char might not be the best design choice). Maybe I'm missing something as to why this will not work?



                      documentclass{article}
                      makeatletter
                      defa{3}
                      defb{2a}
                      defc{1b}
                      def@iterator{%
                      % Expects to be followed by a list of tokens terminated
                      % by a semicolon. If the next character is not a semicolon
                      % then consider it a token to expand.
                      % If the next character is a semicolon then we're done iterating
                      % and can finalising procedures
                      @ifnextchar;@finishIter@processnext%
                      }
                      newcommandtmp@exptok{}
                      def@processnext#1{%
                      % Proces one token and add it to our macro containing
                      % tmp@exptok contains all the tokens expanded once.
                      % So we're now adding this next token.
                      xdeftmp@exptok{unexpandedexpandafter{tmp@exptok}unexpandedexpandafter{#1}}@iterator%
                      }
                      def@finishIter;{globalletexpandedResulttmp@exptokgdeftmp@exptok{}}
                      newcommandexpandtwice[2]{%
                      % First do one expansion
                      @iterator#1;%
                      % Now all tokens are expanded once and contained in expandedResult
                      % Now we reapply it to re-expand every token once again
                      expandafter@iteratorexpandedResult;%
                      % Now store the result in the macro given by the user
                      let#2expandedResult%
                      }
                      makeatother
                      expandtwice{cc}{cTwiceExpanded}
                      % cc -> {1b}{1b} -> 1{2a}1{2a}
                      begin{document}
                      texttt{meaningcTwiceExpanded}%<- now contains 12a12a
                      end{document}


                      Edit: There are of course some special cases like unexpandable macros like textbf which would fail (could potentially be fixed though, by looking for protect after the expansion). Also if you used group brackets ({}), a problem would arise. The latter one probably has a solution with checking the next character for bgroup or something similar.



                      Edit 2: To fix the grouping problem:



                      def@itergroup{%
                      expandafter@iterator@firstofone
                      }
                      def@iterator{%
                      @ifnextcharbgroup{@itergroup}{@ifnextchar;@finishIter@processnext}%
                      }


                      Also, as the OP, I'll be honest and say I haven't yet taken the time to understand how most of the other provided answers work, but I will do so in the near future and select an answer.






                      share|improve this answer


























                      • @UlrichDiez Yup. You're right.

                        – Andreas Storvik Strauman
                        Nov 26 '18 at 20:52











                      • Your @processnext is not suitable for arbitrary sets of tokens: In case one of the tokens processed by @processnextis a macro that processes arguments, @processnext needs to fetch these arguments for the xdef, too...

                        – Ulrich Diez
                        Nov 26 '18 at 21:27











                      • @AndreasStorvikStrauman take a look at my answer, which checks for arguments and fetches them (unfortunately it is only working for macros with undelimited arguments, so still not working for arbitrary tokens). Perhaps if I completely change the approach from being fully expandable inside of an edef I could work that out.

                        – Skillmon
                        Nov 27 '18 at 11:39











                      • @Skillmon I will. Sorry, just very hectic these days. I really want to understand it before I accept it :)

                        – Andreas Storvik Strauman
                        Dec 3 '18 at 8:44
















                      0














                      I'm fairly certain that the following will do expansion of the macros as described in the original question: (In hindsight, using semicolon as termination char might not be the best design choice). Maybe I'm missing something as to why this will not work?



                      documentclass{article}
                      makeatletter
                      defa{3}
                      defb{2a}
                      defc{1b}
                      def@iterator{%
                      % Expects to be followed by a list of tokens terminated
                      % by a semicolon. If the next character is not a semicolon
                      % then consider it a token to expand.
                      % If the next character is a semicolon then we're done iterating
                      % and can finalising procedures
                      @ifnextchar;@finishIter@processnext%
                      }
                      newcommandtmp@exptok{}
                      def@processnext#1{%
                      % Proces one token and add it to our macro containing
                      % tmp@exptok contains all the tokens expanded once.
                      % So we're now adding this next token.
                      xdeftmp@exptok{unexpandedexpandafter{tmp@exptok}unexpandedexpandafter{#1}}@iterator%
                      }
                      def@finishIter;{globalletexpandedResulttmp@exptokgdeftmp@exptok{}}
                      newcommandexpandtwice[2]{%
                      % First do one expansion
                      @iterator#1;%
                      % Now all tokens are expanded once and contained in expandedResult
                      % Now we reapply it to re-expand every token once again
                      expandafter@iteratorexpandedResult;%
                      % Now store the result in the macro given by the user
                      let#2expandedResult%
                      }
                      makeatother
                      expandtwice{cc}{cTwiceExpanded}
                      % cc -> {1b}{1b} -> 1{2a}1{2a}
                      begin{document}
                      texttt{meaningcTwiceExpanded}%<- now contains 12a12a
                      end{document}


                      Edit: There are of course some special cases like unexpandable macros like textbf which would fail (could potentially be fixed though, by looking for protect after the expansion). Also if you used group brackets ({}), a problem would arise. The latter one probably has a solution with checking the next character for bgroup or something similar.



                      Edit 2: To fix the grouping problem:



                      def@itergroup{%
                      expandafter@iterator@firstofone
                      }
                      def@iterator{%
                      @ifnextcharbgroup{@itergroup}{@ifnextchar;@finishIter@processnext}%
                      }


                      Also, as the OP, I'll be honest and say I haven't yet taken the time to understand how most of the other provided answers work, but I will do so in the near future and select an answer.






                      share|improve this answer


























                      • @UlrichDiez Yup. You're right.

                        – Andreas Storvik Strauman
                        Nov 26 '18 at 20:52











                      • Your @processnext is not suitable for arbitrary sets of tokens: In case one of the tokens processed by @processnextis a macro that processes arguments, @processnext needs to fetch these arguments for the xdef, too...

                        – Ulrich Diez
                        Nov 26 '18 at 21:27











                      • @AndreasStorvikStrauman take a look at my answer, which checks for arguments and fetches them (unfortunately it is only working for macros with undelimited arguments, so still not working for arbitrary tokens). Perhaps if I completely change the approach from being fully expandable inside of an edef I could work that out.

                        – Skillmon
                        Nov 27 '18 at 11:39











                      • @Skillmon I will. Sorry, just very hectic these days. I really want to understand it before I accept it :)

                        – Andreas Storvik Strauman
                        Dec 3 '18 at 8:44














                      0












                      0








                      0







                      I'm fairly certain that the following will do expansion of the macros as described in the original question: (In hindsight, using semicolon as termination char might not be the best design choice). Maybe I'm missing something as to why this will not work?



                      documentclass{article}
                      makeatletter
                      defa{3}
                      defb{2a}
                      defc{1b}
                      def@iterator{%
                      % Expects to be followed by a list of tokens terminated
                      % by a semicolon. If the next character is not a semicolon
                      % then consider it a token to expand.
                      % If the next character is a semicolon then we're done iterating
                      % and can finalising procedures
                      @ifnextchar;@finishIter@processnext%
                      }
                      newcommandtmp@exptok{}
                      def@processnext#1{%
                      % Proces one token and add it to our macro containing
                      % tmp@exptok contains all the tokens expanded once.
                      % So we're now adding this next token.
                      xdeftmp@exptok{unexpandedexpandafter{tmp@exptok}unexpandedexpandafter{#1}}@iterator%
                      }
                      def@finishIter;{globalletexpandedResulttmp@exptokgdeftmp@exptok{}}
                      newcommandexpandtwice[2]{%
                      % First do one expansion
                      @iterator#1;%
                      % Now all tokens are expanded once and contained in expandedResult
                      % Now we reapply it to re-expand every token once again
                      expandafter@iteratorexpandedResult;%
                      % Now store the result in the macro given by the user
                      let#2expandedResult%
                      }
                      makeatother
                      expandtwice{cc}{cTwiceExpanded}
                      % cc -> {1b}{1b} -> 1{2a}1{2a}
                      begin{document}
                      texttt{meaningcTwiceExpanded}%<- now contains 12a12a
                      end{document}


                      Edit: There are of course some special cases like unexpandable macros like textbf which would fail (could potentially be fixed though, by looking for protect after the expansion). Also if you used group brackets ({}), a problem would arise. The latter one probably has a solution with checking the next character for bgroup or something similar.



                      Edit 2: To fix the grouping problem:



                      def@itergroup{%
                      expandafter@iterator@firstofone
                      }
                      def@iterator{%
                      @ifnextcharbgroup{@itergroup}{@ifnextchar;@finishIter@processnext}%
                      }


                      Also, as the OP, I'll be honest and say I haven't yet taken the time to understand how most of the other provided answers work, but I will do so in the near future and select an answer.






                      share|improve this answer















                      I'm fairly certain that the following will do expansion of the macros as described in the original question: (In hindsight, using semicolon as termination char might not be the best design choice). Maybe I'm missing something as to why this will not work?



                      documentclass{article}
                      makeatletter
                      defa{3}
                      defb{2a}
                      defc{1b}
                      def@iterator{%
                      % Expects to be followed by a list of tokens terminated
                      % by a semicolon. If the next character is not a semicolon
                      % then consider it a token to expand.
                      % If the next character is a semicolon then we're done iterating
                      % and can finalising procedures
                      @ifnextchar;@finishIter@processnext%
                      }
                      newcommandtmp@exptok{}
                      def@processnext#1{%
                      % Proces one token and add it to our macro containing
                      % tmp@exptok contains all the tokens expanded once.
                      % So we're now adding this next token.
                      xdeftmp@exptok{unexpandedexpandafter{tmp@exptok}unexpandedexpandafter{#1}}@iterator%
                      }
                      def@finishIter;{globalletexpandedResulttmp@exptokgdeftmp@exptok{}}
                      newcommandexpandtwice[2]{%
                      % First do one expansion
                      @iterator#1;%
                      % Now all tokens are expanded once and contained in expandedResult
                      % Now we reapply it to re-expand every token once again
                      expandafter@iteratorexpandedResult;%
                      % Now store the result in the macro given by the user
                      let#2expandedResult%
                      }
                      makeatother
                      expandtwice{cc}{cTwiceExpanded}
                      % cc -> {1b}{1b} -> 1{2a}1{2a}
                      begin{document}
                      texttt{meaningcTwiceExpanded}%<- now contains 12a12a
                      end{document}


                      Edit: There are of course some special cases like unexpandable macros like textbf which would fail (could potentially be fixed though, by looking for protect after the expansion). Also if you used group brackets ({}), a problem would arise. The latter one probably has a solution with checking the next character for bgroup or something similar.



                      Edit 2: To fix the grouping problem:



                      def@itergroup{%
                      expandafter@iterator@firstofone
                      }
                      def@iterator{%
                      @ifnextcharbgroup{@itergroup}{@ifnextchar;@finishIter@processnext}%
                      }


                      Also, as the OP, I'll be honest and say I haven't yet taken the time to understand how most of the other provided answers work, but I will do so in the near future and select an answer.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Nov 26 '18 at 13:57

























                      answered Nov 26 '18 at 13:22









                      Andreas Storvik StraumanAndreas Storvik Strauman

                      2,533418




                      2,533418













                      • @UlrichDiez Yup. You're right.

                        – Andreas Storvik Strauman
                        Nov 26 '18 at 20:52











                      • Your @processnext is not suitable for arbitrary sets of tokens: In case one of the tokens processed by @processnextis a macro that processes arguments, @processnext needs to fetch these arguments for the xdef, too...

                        – Ulrich Diez
                        Nov 26 '18 at 21:27











                      • @AndreasStorvikStrauman take a look at my answer, which checks for arguments and fetches them (unfortunately it is only working for macros with undelimited arguments, so still not working for arbitrary tokens). Perhaps if I completely change the approach from being fully expandable inside of an edef I could work that out.

                        – Skillmon
                        Nov 27 '18 at 11:39











                      • @Skillmon I will. Sorry, just very hectic these days. I really want to understand it before I accept it :)

                        – Andreas Storvik Strauman
                        Dec 3 '18 at 8:44



















                      • @UlrichDiez Yup. You're right.

                        – Andreas Storvik Strauman
                        Nov 26 '18 at 20:52











                      • Your @processnext is not suitable for arbitrary sets of tokens: In case one of the tokens processed by @processnextis a macro that processes arguments, @processnext needs to fetch these arguments for the xdef, too...

                        – Ulrich Diez
                        Nov 26 '18 at 21:27











                      • @AndreasStorvikStrauman take a look at my answer, which checks for arguments and fetches them (unfortunately it is only working for macros with undelimited arguments, so still not working for arbitrary tokens). Perhaps if I completely change the approach from being fully expandable inside of an edef I could work that out.

                        – Skillmon
                        Nov 27 '18 at 11:39











                      • @Skillmon I will. Sorry, just very hectic these days. I really want to understand it before I accept it :)

                        – Andreas Storvik Strauman
                        Dec 3 '18 at 8:44

















                      @UlrichDiez Yup. You're right.

                      – Andreas Storvik Strauman
                      Nov 26 '18 at 20:52





                      @UlrichDiez Yup. You're right.

                      – Andreas Storvik Strauman
                      Nov 26 '18 at 20:52













                      Your @processnext is not suitable for arbitrary sets of tokens: In case one of the tokens processed by @processnextis a macro that processes arguments, @processnext needs to fetch these arguments for the xdef, too...

                      – Ulrich Diez
                      Nov 26 '18 at 21:27





                      Your @processnext is not suitable for arbitrary sets of tokens: In case one of the tokens processed by @processnextis a macro that processes arguments, @processnext needs to fetch these arguments for the xdef, too...

                      – Ulrich Diez
                      Nov 26 '18 at 21:27













                      @AndreasStorvikStrauman take a look at my answer, which checks for arguments and fetches them (unfortunately it is only working for macros with undelimited arguments, so still not working for arbitrary tokens). Perhaps if I completely change the approach from being fully expandable inside of an edef I could work that out.

                      – Skillmon
                      Nov 27 '18 at 11:39





                      @AndreasStorvikStrauman take a look at my answer, which checks for arguments and fetches them (unfortunately it is only working for macros with undelimited arguments, so still not working for arbitrary tokens). Perhaps if I completely change the approach from being fully expandable inside of an edef I could work that out.

                      – Skillmon
                      Nov 27 '18 at 11:39













                      @Skillmon I will. Sorry, just very hectic these days. I really want to understand it before I accept it :)

                      – Andreas Storvik Strauman
                      Dec 3 '18 at 8:44





                      @Skillmon I will. Sorry, just very hectic these days. I really want to understand it before I accept it :)

                      – Andreas Storvik Strauman
                      Dec 3 '18 at 8:44


















                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to TeX - LaTeX Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f461620%2fexpanding-macro-twice%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

                      Calculate evaluation metrics using cross_val_predict sklearn

                      Insert data from modal to MySQL (multiple modal on website)