Expanding macro twice











up vote
2
down vote

favorite












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
    2 days ago












  • 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
    2 days ago










  • @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
    2 days ago












  • @DavidCarlisle No, wait. That's not twice.
    – Andreas Storvik Strauman
    2 days ago






  • 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
    2 days ago















up vote
2
down vote

favorite












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
    2 days ago












  • 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
    2 days ago










  • @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
    2 days ago












  • @DavidCarlisle No, wait. That's not twice.
    – Andreas Storvik Strauman
    2 days ago






  • 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
    2 days ago













up vote
2
down vote

favorite









up vote
2
down vote

favorite











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 2 days ago









Andreas Storvik Strauman

2,322418




2,322418








  • 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
    2 days ago












  • 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
    2 days ago










  • @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
    2 days ago












  • @DavidCarlisle No, wait. That's not twice.
    – Andreas Storvik Strauman
    2 days ago






  • 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
    2 days ago














  • 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
    2 days ago












  • 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
    2 days ago










  • @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
    2 days ago












  • @DavidCarlisle No, wait. That's not twice.
    – Andreas Storvik Strauman
    2 days ago






  • 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
    2 days ago








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
2 days ago






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
2 days ago














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
2 days ago




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
2 days ago












@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
2 days ago






@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
2 days ago














@DavidCarlisle No, wait. That's not twice.
– Andreas Storvik Strauman
2 days ago




@DavidCarlisle No, wait. That's not twice.
– Andreas Storvik Strauman
2 days ago




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
2 days ago




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
2 days ago










4 Answers
4






active

oldest

votes

















up vote
5
down vote













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






























    up vote
    3
    down vote













    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
      2 days ago


















    up vote
    1
    down vote













    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 could, 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`)=1 %
    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






























      up vote
      0
      down vote













      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
        8 hours ago










      • 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
        8 hours ago











      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',
      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








      up vote
      5
      down vote













      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



























        up vote
        5
        down vote













        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

























          up vote
          5
          down vote










          up vote
          5
          down vote









          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 2 days ago

























          answered 2 days ago









          David Carlisle

          478k3811071841




          478k3811071841






















              up vote
              3
              down vote













              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
                2 days ago















              up vote
              3
              down vote













              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
                2 days ago













              up vote
              3
              down vote










              up vote
              3
              down vote









              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 yesterday

























              answered 2 days ago









              Skillmon

              20.5k11941




              20.5k11941












              • Sorry. I really should have explicitly said that it's not only the first expandable token.
                – Andreas Storvik Strauman
                2 days ago


















              • Sorry. I really should have explicitly said that it's not only the first expandable token.
                – Andreas Storvik Strauman
                2 days ago
















              Sorry. I really should have explicitly said that it's not only the first expandable token.
              – Andreas Storvik Strauman
              2 days ago




              Sorry. I really should have explicitly said that it's not only the first expandable token.
              – Andreas Storvik Strauman
              2 days ago










              up vote
              1
              down vote













              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 could, 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`)=1 %
              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



























                up vote
                1
                down vote













                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 could, 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`)=1 %
                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

























                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  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 could, 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`)=1 %
                  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 could, 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`)=1 %
                  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 7 hours ago

























                  answered yesterday









                  Ulrich Diez

                  3,785515




                  3,785515






















                      up vote
                      0
                      down vote













                      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
                        8 hours ago










                      • 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
                        8 hours ago















                      up vote
                      0
                      down vote













                      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
                        8 hours ago










                      • 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
                        8 hours ago













                      up vote
                      0
                      down vote










                      up vote
                      0
                      down vote









                      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 15 hours ago

























                      answered 16 hours ago









                      Andreas Storvik Strauman

                      2,322418




                      2,322418












                      • @UlrichDiez Yup. You're right.
                        – Andreas Storvik Strauman
                        8 hours ago










                      • 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
                        8 hours ago


















                      • @UlrichDiez Yup. You're right.
                        – Andreas Storvik Strauman
                        8 hours ago










                      • 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
                        8 hours ago
















                      @UlrichDiez Yup. You're right.
                      – Andreas Storvik Strauman
                      8 hours ago




                      @UlrichDiez Yup. You're right.
                      – Andreas Storvik Strauman
                      8 hours ago












                      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
                      8 hours ago




                      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
                      8 hours ago


















                       

                      draft saved


                      draft discarded



















































                       


                      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

                      Quarter-circle Tiles

                      build a pushdown automaton that recognizes the reverse language of a given pushdown automaton?

                      Mont Emei