
명령에 별표 버전을 추가하는 메타 매크로를 어떻게 작성할 수 있습니까?
사용 목적은 다음과 같습니다.
\newcommand\foo[1]{foo is #1}
\addstarred\foo[2]{foo is #1, bar is #2}
답변1
suffix
David Kastrup의 패키지에는 이미 방법이 제공되어 있습니다 . 말할 필요도 없이 기발한 트릭이 가득합니다.
당신은 말할 수 있습니다
\usepackage{suffix}
\newcommand{\foo}[1]{foo is #1}
\WithSuffix\newcommand\foo*[2]{foo is #1, bar is #2}
목표가 어떻게 달성되는지 확인하는 것이 유익할 수 있습니다.
두 번째 지시 이후에 수행하면 \show\foo
다음을 찾습니다.
> \foo=\protected macro:
->\WSF@suffixcheck \foo .
suffix
그래서 우리는 e-TeX(요즘에는 문제가 되지 않음)가 필요하다는 것을 배우고 \foo
를 의미하도록 재정의합니다 \WSF@suffixcheck\foo
. 그래서 우리는 를 추가 \makeatletter
하고 시도 \show\WSF@suffixcheck
합니다.
> \WSF@suffixcheck=macro:
#1->\begingroup \def \reserved@a {#1}\futurelet \reserved@b \WSF@suffixcheckii
따라서 인수는 다음 위치에 저장됩니다 \reserved@a
.
\futurelet\reserved@b\WSF@suffixcheckii
실행됩니다. 이는 을 \reserved@b
따르는 토큰과 동일하게 만듭니다 \WSF@suffixcheckii
. 전화가
\foo{foo}
그러면 \reserved@b
될 것이다 \bgroup
; 전화가 오면
\foo*{foo}{bar}
그러면 \reserved@b
될 것입니다 *
. 이제 우리는 무엇을 하는지 알아야 합니다 \WSF@suffixcheckii
:
> \WSF@suffixcheckii=macro:
->\ifcsname \expandafter \SuffixName \reserved@a \reserved@b \endcsname
\expandafter \WSF@suffixcheckiii \else \expandafter \WSF@suffixcheckiv \fi .
좋아, 다음 경우에 무슨 일이 일어나는지 봅시다 \foo{foo}
: \reserved@a
로 확장되고 \foo
, 는 \reserved@b
( \bgroup
확장 불가능)이므로 TeX는 처음으로 다음과 같이 제시됩니다.
\ifcsname\SuffixName\foo\reserved@b\endcsname
그리고 \SuffixName
다음과 같이 정의됩니다.
> \SuffixName=\long macro:
#1->WSF:\string #1 \meaning .
그래서 다음 단계는
\ifcsname WSF:\string\foo \meaning\reserved@b\endcsname
그리고 우리는 마침내 얻습니다
\ifcsname WSF:\foo begin-group character {\endcsname
여기서 모든 문자의 범주 코드는 12입니다(그러나 공백은 10입니다). \foo*{foo}{bar}
우리가 얻을 경우
\ifcsname WSF:\foo the character *\endcsname
명령이 \csname WSF:\foo begin-group character {\endcsname
정의되지 않았으므로 잘못된 분기를 따릅니다.
\expandafter \WSF@suffixcheckiv \fi
그것은 단순히 떠난다
\WSF@suffixcheckiv{foo}
입력 스트림에서. 이제 \show\WSF@suffixcheckiv
준다
> \WSF@suffixcheckiv=macro:
->\expandafter \endgroup \csname \expandafter \NoSuffixName \reserved@a \endcsname .
이전에 열린 그룹은 닫혀 있지만 먼저
\csname \expandafter \NoSuffixName \reserved@a \endcsname
로 이루어져. \reserved@a
로 확장된다는 점을 상기하면 \foo
, 우리는 다음을 얻습니다.
\csname \NoSuffixName \foo \endcsname
그리고 \NoSuffixName
는
> \NoSuffixName=macro:
->WSF:\string .
그래서 마침내 우리는 얻습니다
\csname WSF:\string\foo\encsname
좋아, 다음을 발행해 보자 \expandafter\show\csname WSF:\string\foo\endcsname
:
> \WSF:\foo=\long macro:
#1->foo is #1.
즉, 이 복잡한 매크로는 원본 \foo
.
\foo*{foo}{bar}
우리 의 경우에는
\ifcsname WSF:\foo the character *\endcsname
하지만 이 경우에는~이다한정된; 물론
\expandafter\show\csname WSF:\string\foo\space the character *\endcsname
생산하다
> \WSF:\foo the character *=\long macro:
#1#2->foo is #1, bar is #2.
따라서 이름이 복잡한 이 매크로는 -variant로 정의한 것입니다 *
.
이 패키지에서는 거의 모든 토큰을 접미사로 사용할 수 있습니다. 그러나 본질적인 아이디어는 당신이 고안한 것과 다르지 않습니다. 가능한 기존 매크로 이름을 덮어쓰는 것에 대한 보호 기능이 더 좋습니다. 언제 패키지가 하는 일
\WithSuffix\newcommand\foo*[2]{foo is #1, bar is #2}
처리됩니다
원래
\foo
명령을 아래에 저장하십시오.\csname WSF:\string\foo\endcsname
\WithSuffix
(이 단계 에 적용된 선행 작업으로 인해 이미 존재하는 경우\foo
당연히 생략됩니다.)아래에 새 정의를 저장합니다.
\csname WSF:\string\foo\space the character *\endcsname
위에서 설명한 추상 인터페이스를 사용하여 다양한 접미사 중에서 선택하세요.
답변2
해결책에 대한 내 시도는 @egreg 및 @DavidCarlisle이 친절하게 제공한 개선 사항과 함께 아래에 나와 있습니다.
\documentclass{standalone}
\makeatletter
\newcommand\addstarred[1]{%
\expandafter\let\csname\string#1@nostar\endcsname#1%
\edef#1{\noexpand\@ifstar\expandafter\noexpand\csname\string#1@star\endcsname\expandafter\noexpand\csname\string#1@nostar\endcsname}%
\expandafter\newcommand\csname\string#1@star\endcsname%
}
\makeatother
\newcommand\foo[1]{foo is #1}
\addstarred\foo[2]{foo is #1, bar is #2}
\begin{document}
\foo{red} --- \foo*{red}{green}
\end{document}
결과:
설명:
- 명령의 현재 정의 사본
\foo
은 로 저장됩니다\\foo@nostar
. \foo
별표를 확인하고 또는\\foo@star
를 호출하도록 명령이 재정의되었습니다\\foo@nostar
. 이는edef
명령이 호출될 때마다가 아니라 구성된 토큰 이름이 제자리에서 확장될 수 있도록 수행됩니다 .- for
\newcommand
가\\foo@star
시작되고 다음과 같이 정의의 나머지 부분을 사용합니다\addstarred\foo
.