macros

Расширение аргументов перед вызовом макроса

Я бьюсь головой об это уже несколько дней.У меня есть макрос,который принимает имя макроса и его аргументы.Затем он немного переставляет аргументы,а затем вызывает переданный макрос с перестановленными аргументами,и все заканчивается следующим образом:

#1{\arga}{\argb}{\argc}

где arga ... \argc — обрабатываемые аргументы. Однако. Мне нужно, чтобы \arga ... \argc полностью развернут перед вызовом макроса, хранящегося в #1 . Я не могу на всю жизнь решить это после нескольких дней игры с \expandafter , \noexpand , etextools и т. Д. Я не могу использовать expl3 , и я действительно предпочел бы не использовать etextools , но доступен etoolbox . Вот МВЕ:

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \def\argb{#3}%
  \def\argc{#4}%
  #1{\arga}{\argb}{\argc}}

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

Это приводит к «\ arga \ argb \ argc», но я хочу «arg1arg2arg3». \expandafter сделает это в \x , но не для трех аргументов подряд. etextools есть несколько макросов для этого, но я действительно хочу этого избежать (в некотором роде он конфликтует с etoolbox , и у меня должен быть etoolbox ). Я не мог заставить макросы etextools работать, даже когда пытался ( \ExpandNextTwo и т. д .)

UPDATE:Я понял,что в моем случае args может содержать надежные макросы,такие как:

\documentclass{article}
\usepackage{etoolbox}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \edef\argb{\ifstrequal{#3}{arg2}{arg2}{}}%
  \def\argc{#4}%
  {\protected\z{\noexpand#1{\arga}{\argb}{\argc}}\z}}

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

В этом случае (используя ответ egreg в качестве примера)он не полностью развернут.Как отмечают Джозеф и egreg ниже,это не выполнимо,в таких случаях нужно просто использовать неробастные макросы,например.Я оставлю вопрос в силе,поскольку он информативен.

«Классический» подход заключается в использовании \expandafter

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \def\argb{#3}%
  \def\argc{#4}%
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter#1%
    \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
      {\expandafter\expandafter\expandafter\arga\expandafter\expandafter\expandafter}%
        \expandafter\expandafter\expandafter{\expandafter\argb\expandafter}\expandafter
          {\argc}}

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

где нам нужно так много из них, чтобы расширить arg3 , затем arg2 и, наконец, arg1 . (Это то, что эффективно заключено в expl3 expl3 \exp_args:Nooo ).

Правило количества необходимых нам \expandafter s — 2 n — 1, где n — это количество токенов, которые мы хотим расширить. Таким образом, для одного токена где-то впереди нам нужно только по одному \expandafter в каждом месте, которое нужно «пропустить», для расширения двух токенов (второго, затем первого) нам нужно три \expandafter s, для трех токенов (как в текущем случае ) нам нужно семь \expandafter s, и так один. Это легче всего увидеть, если вы напишете/распечатаете короткую секунду и вычеркнете команды так, как их читает TeX: вы обнаружите, что все работает.

Имея доступный e-TeX, мы можем использовать \edef и \unexpanded :

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \def\argb{#3}%
  \def\argc{#4}%
  \begingroup
    \edef\x{%
      \endgroup
      \noexpand#1
        {\unexpanded\expandafter{\arga}}%
        {\unexpanded\expandafter{\argb}}%
        {\unexpanded\expandafter{\argc}}%
    }%
  \x
}    

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

(Вы можете сделать то же самое без e-TeX, используя серию токов, но это немного сбивает с толку, поэтому я обычно этого не делаю.)


В вопросе говорится, что нет expl3 , но для контраста подход, использующий минимум функций, которые он предоставляет, будет читать

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\def\x#1#2#3#4{
  \def\arga{#2}
  \def\argb{#3}
  \def\argc{#4}
  \exp_args:Nooo#1\arga\argb\argc
}    
\ExplSyntaxOff
\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

который, я надеюсь, намного читабельнее. (Я, вероятно, хотел бы использовать \exp_args:NVVV , так как мы используем «значение, хранящееся в переменной», но эта функция не определена заранее, поэтому я избегал ее здесь.)




Если вы действительно хотите, чтобы аргументы были полностью расширены, то

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \begingroup\edef\z{\endgroup\noexpand#1{#2}{#3}{#4}}\z
}

\def\y#1#2#3{\detokenize{#1#2#3}}

\def\foo{This is foo}

\texttt{\x\y{arg1}{arg2}{arg3\foo}}

\end{document}

приведет к печати

arg1arg2arg3This is foo

тогда как решения на основе \expandafter будут печатать

arg1arg2arg\foo