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}
macros expansion
|
show 4 more comments
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}
macros expansion
2
you haven't really defined what expanding twice means, normally i'd take it to meanexpandafterexpandafterexpandafterc
but1
isn't expandable so that gives you1b
you say you want12a
but do you want to expand all tokens inc
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 ofc
wasdefc{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 inc
by one step though.
– Andreas Storvik Strauman
2 days ago
@DavidCarlisle, for the case when the definition isdefc{1b1b}
, I then guess I'd want the result to be12a12a
because then, since 1 can't be expanded further, it stays as a1
andb
is2a
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
|
show 4 more comments
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}
macros expansion
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
macros expansion
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 meanexpandafterexpandafterexpandafterc
but1
isn't expandable so that gives you1b
you say you want12a
but do you want to expand all tokens inc
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 ofc
wasdefc{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 inc
by one step though.
– Andreas Storvik Strauman
2 days ago
@DavidCarlisle, for the case when the definition isdefc{1b1b}
, I then guess I'd want the result to be12a12a
because then, since 1 can't be expanded further, it stays as a1
andb
is2a
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
|
show 4 more comments
2
you haven't really defined what expanding twice means, normally i'd take it to meanexpandafterexpandafterexpandafterc
but1
isn't expandable so that gives you1b
you say you want12a
but do you want to expand all tokens inc
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 ofc
wasdefc{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 inc
by one step though.
– Andreas Storvik Strauman
2 days ago
@DavidCarlisle, for the case when the definition isdefc{1b1b}
, I then guess I'd want the result to be12a12a
because then, since 1 can't be expanded further, it stays as a1
andb
is2a
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
|
show 4 more comments
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.
add a comment |
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}
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}%
}
Sorry. I really should have explicitly said that it's not only the first expandable token.
– Andreas Storvik Strauman
2 days ago
add a comment |
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 ⟨list of not yet expanded tokens⟩ and maintains a ⟨list of already expanded tokens⟩ as follows:
Step 1:
Check whether the ⟨list of not yet expanded tokens⟩ is empty.
If so: Deliver the ⟨list of already expanded tokens⟩.
If not so:
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is not expandable, remove it from the ⟨list of not yet expanded tokens⟩ and add it at the end of the ⟨list of already expanded tokens⟩.
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is expandable, expand it and remove the result of that expansion from the ⟨list of not yet expanded tokens⟩ and add the result of that expansion at the end of the ⟨list of already expanded tokens⟩.
Repeat Step 1.
One crucial point hereby is "removing the result of that expansion from the ⟨list of not yet expanded tokens⟩ and adding the result of that expansion at the end of the ⟨list of already expanded tokens⟩".
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 ⟨list of not yet expanded tokens⟩ before that expansion took place.
Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}
, while the ⟨list of not yet expanded tokens⟩ holds the following content:macro ABC Whatsoever
Now you need to have macro
expanded once. After that, the ⟨list of not yet expanded tokens⟩ holds the following content:ABC Whatsoever
.
Now you need to move the result from expanding macro
towards the ⟨list of already expanded tokens⟩.
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 ⟨list of not yet expanded tokens⟩?
(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 ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨top-level-expansion of next but one token⟩
.
In case the next but one token is not expandable, the replacement-text ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨next but one token⟩
.
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 doexpandafter 1expandafter 2expandafter 3foo
, you will get123bar
:
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
add a comment |
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.
@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@processnext
is a macro that processes arguments,@processnext
needs to fetch these arguments for thexdef
, too...
– Ulrich Diez
8 hours ago
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
edited 2 days ago
answered 2 days ago
David Carlisle
478k3811071841
478k3811071841
add a comment |
add a comment |
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}
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}%
}
Sorry. I really should have explicitly said that it's not only the first expandable token.
– Andreas Storvik Strauman
2 days ago
add a comment |
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}
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}%
}
Sorry. I really should have explicitly said that it's not only the first expandable token.
– Andreas Storvik Strauman
2 days ago
add a comment |
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}
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}%
}
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}
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}%
}
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
add a comment |
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
add a comment |
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 ⟨list of not yet expanded tokens⟩ and maintains a ⟨list of already expanded tokens⟩ as follows:
Step 1:
Check whether the ⟨list of not yet expanded tokens⟩ is empty.
If so: Deliver the ⟨list of already expanded tokens⟩.
If not so:
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is not expandable, remove it from the ⟨list of not yet expanded tokens⟩ and add it at the end of the ⟨list of already expanded tokens⟩.
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is expandable, expand it and remove the result of that expansion from the ⟨list of not yet expanded tokens⟩ and add the result of that expansion at the end of the ⟨list of already expanded tokens⟩.
Repeat Step 1.
One crucial point hereby is "removing the result of that expansion from the ⟨list of not yet expanded tokens⟩ and adding the result of that expansion at the end of the ⟨list of already expanded tokens⟩".
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 ⟨list of not yet expanded tokens⟩ before that expansion took place.
Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}
, while the ⟨list of not yet expanded tokens⟩ holds the following content:macro ABC Whatsoever
Now you need to have macro
expanded once. After that, the ⟨list of not yet expanded tokens⟩ holds the following content:ABC Whatsoever
.
Now you need to move the result from expanding macro
towards the ⟨list of already expanded tokens⟩.
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 ⟨list of not yet expanded tokens⟩?
(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 ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨top-level-expansion of next but one token⟩
.
In case the next but one token is not expandable, the replacement-text ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨next but one token⟩
.
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 doexpandafter 1expandafter 2expandafter 3foo
, you will get123bar
:
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
add a comment |
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 ⟨list of not yet expanded tokens⟩ and maintains a ⟨list of already expanded tokens⟩ as follows:
Step 1:
Check whether the ⟨list of not yet expanded tokens⟩ is empty.
If so: Deliver the ⟨list of already expanded tokens⟩.
If not so:
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is not expandable, remove it from the ⟨list of not yet expanded tokens⟩ and add it at the end of the ⟨list of already expanded tokens⟩.
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is expandable, expand it and remove the result of that expansion from the ⟨list of not yet expanded tokens⟩ and add the result of that expansion at the end of the ⟨list of already expanded tokens⟩.
Repeat Step 1.
One crucial point hereby is "removing the result of that expansion from the ⟨list of not yet expanded tokens⟩ and adding the result of that expansion at the end of the ⟨list of already expanded tokens⟩".
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 ⟨list of not yet expanded tokens⟩ before that expansion took place.
Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}
, while the ⟨list of not yet expanded tokens⟩ holds the following content:macro ABC Whatsoever
Now you need to have macro
expanded once. After that, the ⟨list of not yet expanded tokens⟩ holds the following content:ABC Whatsoever
.
Now you need to move the result from expanding macro
towards the ⟨list of already expanded tokens⟩.
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 ⟨list of not yet expanded tokens⟩?
(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 ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨top-level-expansion of next but one token⟩
.
In case the next but one token is not expandable, the replacement-text ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨next but one token⟩
.
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 doexpandafter 1expandafter 2expandafter 3foo
, you will get123bar
:
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
add a comment |
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 ⟨list of not yet expanded tokens⟩ and maintains a ⟨list of already expanded tokens⟩ as follows:
Step 1:
Check whether the ⟨list of not yet expanded tokens⟩ is empty.
If so: Deliver the ⟨list of already expanded tokens⟩.
If not so:
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is not expandable, remove it from the ⟨list of not yet expanded tokens⟩ and add it at the end of the ⟨list of already expanded tokens⟩.
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is expandable, expand it and remove the result of that expansion from the ⟨list of not yet expanded tokens⟩ and add the result of that expansion at the end of the ⟨list of already expanded tokens⟩.
Repeat Step 1.
One crucial point hereby is "removing the result of that expansion from the ⟨list of not yet expanded tokens⟩ and adding the result of that expansion at the end of the ⟨list of already expanded tokens⟩".
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 ⟨list of not yet expanded tokens⟩ before that expansion took place.
Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}
, while the ⟨list of not yet expanded tokens⟩ holds the following content:macro ABC Whatsoever
Now you need to have macro
expanded once. After that, the ⟨list of not yet expanded tokens⟩ holds the following content:ABC Whatsoever
.
Now you need to move the result from expanding macro
towards the ⟨list of already expanded tokens⟩.
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 ⟨list of not yet expanded tokens⟩?
(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 ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨top-level-expansion of next but one token⟩
.
In case the next but one token is not expandable, the replacement-text ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨next but one token⟩
.
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 doexpandafter 1expandafter 2expandafter 3foo
, you will get123bar
:
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
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 ⟨list of not yet expanded tokens⟩ and maintains a ⟨list of already expanded tokens⟩ as follows:
Step 1:
Check whether the ⟨list of not yet expanded tokens⟩ is empty.
If so: Deliver the ⟨list of already expanded tokens⟩.
If not so:
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is not expandable, remove it from the ⟨list of not yet expanded tokens⟩ and add it at the end of the ⟨list of already expanded tokens⟩.
- In case the first element/the first token of the ⟨list of not yet expanded tokens⟩ is expandable, expand it and remove the result of that expansion from the ⟨list of not yet expanded tokens⟩ and add the result of that expansion at the end of the ⟨list of already expanded tokens⟩.
Repeat Step 1.
One crucial point hereby is "removing the result of that expansion from the ⟨list of not yet expanded tokens⟩ and adding the result of that expansion at the end of the ⟨list of already expanded tokens⟩".
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 ⟨list of not yet expanded tokens⟩ before that expansion took place.
Assume, e.g., a macro which is defined as follows: defmacro#1#2#3{ABC}
, while the ⟨list of not yet expanded tokens⟩ holds the following content:macro ABC Whatsoever
Now you need to have macro
expanded once. After that, the ⟨list of not yet expanded tokens⟩ holds the following content:ABC Whatsoever
.
Now you need to move the result from expanding macro
towards the ⟨list of already expanded tokens⟩.
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 ⟨list of not yet expanded tokens⟩?
(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 ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨top-level-expansion of next but one token⟩
.
In case the next but one token is not expandable, the replacement-text ofexpandafter⟨next token⟩⟨next but one token⟩
will be⟨next token⟩⟨next but one token⟩
.
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 doexpandafter 1expandafter 2expandafter 3foo
, you will get123bar
:
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
edited 7 hours ago
answered yesterday
Ulrich Diez
3,785515
3,785515
add a comment |
add a comment |
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.
@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@processnext
is a macro that processes arguments,@processnext
needs to fetch these arguments for thexdef
, too...
– Ulrich Diez
8 hours ago
add a comment |
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.
@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@processnext
is a macro that processes arguments,@processnext
needs to fetch these arguments for thexdef
, too...
– Ulrich Diez
8 hours ago
add a comment |
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.
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.
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@processnext
is a macro that processes arguments,@processnext
needs to fetch these arguments for thexdef
, too...
– Ulrich Diez
8 hours ago
add a comment |
@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@processnext
is a macro that processes arguments,@processnext
needs to fetch these arguments for thexdef
, 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 @processnext
is 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 @processnext
is a macro that processes arguments, @processnext
needs to fetch these arguments for the xdef
, too...– Ulrich Diez
8 hours ago
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
2
you haven't really defined what expanding twice means, normally i'd take it to mean
expandafterexpandafterexpandafterc
but1
isn't expandable so that gives you1b
you say you want12a
but do you want to expand all tokens inc
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 ofc
wasdefc{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 be12a12a
because then, since 1 can't be expanded further, it stays as a1
andb
is2a
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