> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/ko/more-topics/24-how-tex-macros-actually-work-part-6.md).

# TeX 매크로는 실제로 어떻게 작동하는가: 6부

[1부](/latex/ko/more-topics/19-how-tex-macros-actually-work-part-1.md) [2부](/latex/ko/more-topics/20-how-tex-macros-actually-work-part-2.md) [3부](/latex/ko/more-topics/21-how-tex-macros-actually-work-part-3.md) [4부](/latex/ko/more-topics/22-how-tex-macros-actually-work-part-4.md) [5부](/latex/ko/more-topics/23-how-tex-macros-actually-work-part-5.md) [6부](/latex/ko/more-topics/24-how-tex-macros-actually-work-part-6.md)

## 소개와 개요: 지금까지의 이야기

이 시리즈의 앞선 5부에서 우리는 다음을 보았다:

* TeX가 입력 파일 안의 문자들을 어떻게 읽고, 범주 코드를 사용해 서로 다른 문자 “범주”를 인식한 뒤 그것들을 문자 토큰과 명령 토큰으로 변환하는지;
* 매크로는 사실상 네 부분으로 구성되어 있다는 것:

```
<TeX macro primitive><macro name><parameter text>{<replacement text>}
```

여기서:

* `<TeX macro primitive>` = 다음 중 하나 `\def`, `\edef`, `\gdef` 또는 `\xdef`;
* `<매크로 이름>`= 매크로의 이름, 예를 들어 `\foo`;
* `<매개변수 텍스트>` “null”(존재하지 않음)일 수도 있고, 구분자 토큰과 매크로 매개변수 토큰으로 이루어진 문자열일 수도 있다;
* `<대체 텍스트>` 는 매크로의 실제 본문이다: 매크로를 호출할 때 “실행” (확장)되는 부분이다.
* 어떻게 `<매개변수 텍스트>` 부분이 다양한 토큰을 포함할 수 있으며, TeX가 이 부분을 매크로 호출을 원래 정의와 맞춰보고 매크로에 사용된 인자들을 알아내기 위한 “토큰 템플릿”으로 사용하고, 또한 TeX가 매크로 사용이 원래 정의와 일치하기를 기대하는 방식;
* TeX 내부에서 매크로 정의는 다음을 나타내는 토큰들의 연속된 시퀀스로 저장된다는 것: `<매개변수 텍스트>` 및 `<대체 텍스트>` 부분들.

매크로 명령을 사용하면 TeX는 먼저 그것이 매개변수를 받는지 확인한다. 그렇다면 TeX는 그다음 매크로 호출에서 실제로 사용된 *인자* 를 식별해야 한다. TeX는 메모리에 저장해 둔 “토큰 템플릿” 정의와 매크로 호출을 대조해야 한다. 구체적으로 TeX는 매크로의 내부(저장된) 정의의 `<매개변수 텍스트>` 부분을 템플릿으로 삼아 다음을 골라낼 수 있다 *토큰* 이 실제 인자인 토큰들, 그리고 어떤 것들이 *토큰* 단지 구분자 역할을 하기 위한 것들인지.

## 매크로 확장의 의미

이제 마침내, 가장 중요한 주제로 넘어갈 준비가 되었다: TeX가 매크로 인자를 처리하고 실제로 매크로를 실행하는 방법, 즉 TeX가 다음과 부르는 과정 *매크로 확장*.

### 하지만 먼저, 짧은 예제 하나: 뭔가 이상하지 않은가?

TeX가 매크로와 그 인자를 처리하는 메커니즘을 설명하기 위한 상황을 설정해 보자. 여기서는 우리가 고려해야 할 쟁점을 보여 주는 짧은 예제를 사용하겠다.

#### 인자는 먼저 토큰으로 변환된다

다음 예제는 다음 책 114–115쪽에서 논의된 예제를 바탕으로 한다: [The Advanced TeXbook](https://www.amazon.co.uk/Advanced-Texbook-David-Salomon/dp/0387945563) David Salomon이 쓴 책이다. 이것을 택한 이유는 매우 짧은 TeX 매크로 안에 핵심 아이디어를 잘 담고 있기 때문이다.

일반적인 TeX/LaTeX 작업에서 `$` $ 기호는 범주 코드 3(“수학 전환”)을 가지며, TeX를 인라인 수학 모드(`$...$`) 또는 디스플레이 수학 모드(`$$...$$`)로 전환한다—물론 LaTeX에서는 `\(..\)` 및 `\[..\]` 를 같은 목적으로 사용한다.

어떤 매크로를 만들어 $ 기호의 범주 코드를 예를 들어 11로 바꾸어 일반 문자처럼 조판할 수 있도록 하고 싶다고 하자. TeX의 원시 명령 `$` 을 사용할 수 있고, 그러한 매크로에 대한 첫 시도인 `\catcode` 을 `\docat`라고 하면, 다음과 같을 수 있다.

```
\def\docat #1{\catcode`\$=11 #1}
```

하지만 이렇게 사용해 보려 하면

```
\begin{document}
\def\docat #1{\catcode`\$=11 #1}
I paid \docat{$90} for that book.
\end{document}
```

TeX이 다음을 조판할 것으로 기대한다: `I paid $90 for that book.` 하지만 오류 메시지와 함께 실패한다:

```
! Missing $ inserted.
<inserted text>
                $
<to be read again>
                   \par
l.7
```

오류를 보면 우리 매크로의 인자에 사용된 `$` $ 기호가 여전히 TeX로 하여금 수학 모드를 조판하도록 유발하는 듯하다; 분명 TeX는 *하지 않았다* 다음의 범주 코드를 변경: `$` 우리 매크로의 인자에 사용된 $ 기호(`$90`)는. 그렇다면 의문은 *왜일까요* 왜 TeX는 다음의 범주 코드를 11로 바꾸어 일반 문자로 조판하지 않았을까? `$` 짧게 말하면 TeX는 먼저 매크로 인자를 토큰으로 변환하고 **이전의** 그것들을 다음의 토큰 목록에 넣기 때문이다 `<대체 텍스트>`—하지만 그 밑바탕 메커니즘은 훨씬 더 자세히 살펴보겠다.

기억해야 할 것은, TeX이 텍스트/문자를 사용한다는 우리의 개념은 TeX가 읽고 있는 파일의 내용에만 해당한다는 점이다: TeX가 어떤 문자든 읽어 들이는 순간 우리는 *토큰*의 세계에 들어가게 된다. TeX 매크로 호출은 *토큰*와 작업하며 실제 *기록된/텍스트 표현* 의 TeX/LaTeX 명령과는 다르다—예제를 따라가며 더 분명해질 것이다.

처음에는 우리가 `\docat` 에서의 매크로 사용이 `I paid \docat{$90} for that book.` 동등한 TeX(또는 LaTeX) 코드를 직접 쓰는 것과 같다고 생각할 수도 있다—예를 들어 다음 코드는 *실제로* 작동한다:

```
\begin{document}
I paid \catcode`\$=11 $90 for that book.
\end{document}
```

![Overleaf에서 실행 중인 TeX 코드](/files/c70c8661165bc369aecf97fdfc63a06a31913dba)

그러나 앞서 보았듯이, TeX가 매크로 인자를 처리하는 방식은 결과를(`! Missing $ inserted.`)로 만들어 내며, 이는 TeX 코드를 직접 써 놓은 것과는 상당히 다르다: 이제 우리는 *왜일까요* 무슨 일이 일어나는지 살펴보겠다.

### 토큰 목록으로서의 매크로와 인자

다음의 동작을 완전히 이해하려면 `\docat` 매크로와 그 인자(`$90`) 그리고 그것이 왜 실패하는지를 이해하려면, 우리는 다시 한 번 다음의 정의를 시각화해야 한다 `\docat` 매크로와 ( \docat 가 호출될 때 사용된) 인자들을 다음으로 보아야 한다 *토큰 목록*, 문자들의 연속이 아니라.

TeX가 입력 텍스트를 스캔하면 `\docat` 를 매크로 명령으로 인식할 것이다; 그다음 그것이 매개변수를 받는지 확인한다—TeX가 이를 어떻게 하는지는 세부 사항에 관심 있는 독자를 위해 다음 절에서 설명한다.

#### 세부 사항을 좋아하는 분들을 위해...

매크로가 호출된 뒤, TeX는 (매크로의 저장된 정의 토큰 목록에서) 맨 첫 번째 토큰이 다음인지 확인한다 **종료 일치** 토큰인지 확인한다: 그렇다면 TeX는 그 매크로가 매개변수를 받지 않는다고 확신할 수 있다.

**예제**

다음의 노드 목록 도식은 두 매크로의 토큰 목록을 비교한다:

* `\def\foo A#1B{#1}`: 여기에는 `<매개변수 텍스트>` 의 `A#1B`, 따라서 **종료 일치** 토큰이 **작동하지** 첫 번째 토큰이므로 TeX는 매개변수를 찾으러 간다;
* `\def\foo{X}`: 여기에는 `<매개변수 텍스트>` 부분이 없으므로 따라서 **종료 일치** 토큰이 토큰 목록의 첫 번째이며 TeX는 어떤 매개변수도 찾지 않으려 한다는 것을 안다.

![TeX가 매크로가 매개변수를 받는지 확인하는 방법](/files/d2c8fdf0e05caa40f7fb809f0b491c43824c5f66)

## “대단원”을 향하여: 확장

질문을 다시 떠올려 보자: 왜 다음 매크로는 작동하지 않았는가; 즉, 왜 TeX는 인자에 사용된 어떤 `$` 기호의 범주 코드를 바꾸지 않는가 `\docat` 매크로의 인자에서, 예를 들면 `\docat{$90}`?

```
\begin{document}
\def\docat #1{\catcode`\$=11 #1}
I paid \docat{$90} for that book.
\end{document}
```

앞서 설명했듯이, TeX가 입력을 스캔해 매크로 명령을 인식하면—TeX가 그것을 실행하려는 시점에서—TeX는 먼저 그 매크로가 매개변수를 받는지 확인한다. 그렇다면 TeX는 입력 파일을 더 스캔하여 실제 *인자* 사용자가 이 특정 매크로 호출을 위해 제공한 인자들을 식별해야 한다: TeX는 이를 해야 **이전의** 실제 매크로 코드를 호출할 수 있다. 분명 TeX는 사용자가 매크로에 제공하려는 데이터를 알아내야 한다.

입력에 있는 인자들(사용자의 매크로 호출)을 식별하려면, TeX는 그 매크로의 내부에 저장된 정의를 따르게 된다: 구체적으로는 `<매개변수 텍스트>` 저장된 매크로 정의(토큰 목록)의 부분—일종의 “토큰 템플릿”을 제공한다. 그 “토큰 템플릿”을 사용하여 TeX는 어떤 *토큰* 사용자의 매크로 호출 속 토큰들이 단지 *구분 기호를* (본질적으로 “구두점”)인지, 그리고 어떤 *토큰* 토큰들이 하나의 *인자의 일부를 이루는지*. TeX가 다음을 만나면 **match parameter** 토큰을 저장된 매크로 정의의 `<매개변수 텍스트>` 부분(“토큰 템플릿”)에서 TeX는 만들기 시작해야 한다는 것을 안다 *토큰 목록* 을 그 특정 인자에 대해.

TeX가 사용자의 인자를 식별해야 함을 알아차리자마자, 입력을 스캔해 토큰을 생성하고 그것들을 저장된 매크로 정의와 토큰 단위로 아주 세심하게 대조한다. TeX는 실제로 구분자인 토큰을 감지하거나, 또는 다음의 **종료 일치** 토큰을 감지할 때까지 그 인자를 위한 토큰 수집을 계속한다: 어느 경우든 TeX는 이제 그 인자를 이루는 토큰 찾기를 멈출 때임을 안다.

### \docat 매크로가 실패한 이유

앞서 언급했듯이, *이전의* TeX가 실제로 매크로를 호출하려면 그 매크로와 함께 사용될 인자들을 식별하고 준비해야 한다. 그러나 인자(들)를 식별하여 매크로에 넣을 준비를 하려면 TeX는 각 인자를 다음의 형태로 생성해야 한다 *토큰 목록*: 그리고 그것이 바로 `\docat`의 실패 이유이다.

우리 예제에서는 `\docat` 에 다음을 인자로 제공했다 `$90` 하지만 그 인자는 먼저 *토큰 목록으로 변환된다* TeX가 매크로 호출을 스캔하는 동안—인자는 토큰으로 변환된다 *이전의* 매크로가 실제로 호출되기 전이다. 여기서 인자 `$90`, TeX는 세 개의 문자 토큰을 생성할 것이다: 각각 `$`, `9` 및 `0`.

다음 그림은 인자에 대해 생성된 토큰 목록을 보여 준다 `$90`, 그것이 다음의 본문으로 입력되기 전의 상태를 `\docat` 매크로:

![매크로 인자에 대해 생성된 TeX 토큰 목록](/files/cbcab6672f05d454599bd1e1e49154ed4b345153)

위 그림에서 인자 토큰 목록에 다음이 포함되어 있음을 분명히 볼 수 있다 `$` 범주 코드 3을 바탕으로 한 문자 토큰으로서의

1부부터 3부까지 보았듯이, 문자 토큰은 범주 코드 값을 사용하여 생성되며 *문자가 읽혀 들어오는 시점에 적용된다*—즉, 인자의 토큰 목록이 만들어질(토큰으로 바뀔) 때의 값이다. 인자들이 토큰화되는 시점에는 `\docat` 매크로는 아직 실행되지 않았으므로 우리가 매크로 호출에 넣은 범주 코드 변경(``\catcode`\$=11``) *작동하지* )은 인자 토큰을 생성하는 데 사용되는 범주 코드에 영향을 주지 못한다.

TeX가 다음의 인자를 나타내는 토큰 목록을 생성하면 `$90`, 그 세 문자 토큰은 실제 매크로에 입력된다 `<대체 텍스트>`. 그러나 그 결과 `$` 이 다음으로 입력되는 것이 *문자 토큰* 범주 코드 3, 즉 “math on”을 사용해 생성된 것이라는 점이다. 그리고 보았듯이 일단 문자 토큰이 형성되면 붙어 있는 범주 코드는 영구적이다. 다음은 `$` 는 *작동하지* 매크로에 입력되지만 *문자로서가 아니라*, 다음과 같은 *문자 토큰* 를 기반으로 한 `$` 것으로

### \docat 실행: 매크로 확장

TeX는 매크로를 “실행”하는 과정을 다음이라고 부른다 *매크로 확장*; 이 저자 의견으로는 약간 헷갈리지만 받아들여진 용어이므로 계속 사용하겠다.

#### 매크로 확장의 진짜 의미

TeX가 다음을 감지한 후 `\docat` 사용자 입력의 명령은 인자들을 스캔해 그 인자(`$90`)에 대한 토큰 목록을 생성한다. 매크로를 실행(확장)하려면 TeX는 사용자 입력 파일에서 시선을 돌려 다음에 들어 있는 토큰들을 읽기 시작한다 `\docat`의 `<대체 텍스트>` TeX 메모리에 저장된 토큰 목록에.

TeX가 다음을 처리하면서 `\docat`의 정의를 보면, 원래 매크로를 정의하는 데 사용된 토큰들의 연속을 보고 실행하게 된다(`**catcode**`, ``**`**``, `**\$**`, `**=**`, `**1**`, `**1**`, `**#1**`).

다음 그림은 다음을 확장하는 과정을 보여 준다 `\docat` 매크로: TeX는 입력 파일에서 토큰을 더 이상 가져오지 않고 다음에서 토큰 읽기를 시작한다 `<대체 텍스트>` 부분의 `\docat` 메모리에 저장된 매크로 정의. TeX는 미리 준비된 이 토큰들을 실행하다가 다음을 만나면 멈춘다 **출력 매개변수** 토큰인데, 이는 TeX가 이 지점에서 인자 토큰을 읽어 들여(“주입”) “실행”하라는 지시이다. 우리 예제에서는 그것이 다음을 나타내는 세 문자 토큰이다 `$90` 그리고 이는 오류를 낳는데, 미리 준비된 다음의 문자 토큰이 `$` 범주 코드 3을 가지기 때문이다. 우리는 문자가 아니라 문자 토큰을 다루고 있으므로 `$` 는 앞서 다음의 토큰들이 일으킨 범주 코드 변경의 영향을 받지 않는다 ``\catcode`\$=11``.

![\docat 매크로를 확장하는 과정 보여 주기](/files/153ba4bc4968bec388d32015efddf2c8a21b938a)

TeX가 다음을 나타내는 토큰들을 처리한 뒤 ``\catcode`\$=11``, 다음에 대한 범주 코드 변경이 `$` 이제 적용된다. 그러면 TeX는 다음이라는 “특수 토큰”을 만나게 된다 **출력 매개변수** 이는 TeX에게 다음을 하라고 알려 준다 **삽입** 인자에 대한 토큰 목록을. 그러나 그 토큰 목록은 세 개의 문자 *토큰*, 그 첫 번째는 다음에 대한 토큰이다 `$` 이며 거기에 범주 코드 3(“math on”)이 할당되어 있다: 매크로 내부의 이전 범주 코드 변경은 이 문자 토큰에 영향을 줄 수 없으므로 TeX는 그 토큰을 수학 처리를 시작하라는 신호로 취급하고, 그 결과 매크로가 실패한다.

### \docat 매크로를 고칠 수 있을까?

위 논의로부터, 매크로 인자에 나타나는 모든 문자는 토큰화가 이루어지는 시점에 적용 중인 범주 코드로 토큰화된다는 것이 분명하다—우리 예제에서는 그것이 *항상* 전에 `<대체 텍스트>` 의 `\docat` 매크로가 실제로 실행되기 전이다. 그렇다면 매크로 인자의 범주 코드를 어떻게 바꾸도록 보장할 수 있을까?

한 가지 방법은 다음을 수정하는 것이다 `\docat` 를 매개변수가 없는 매크로로 만들어 범주 코드 변경만 수행하게 하는 것이다—이 매크로는 토큰화할 인자가 없다. 그런 다음 두 번째 매크로 `\getarg`즉, 단일 매개변수를 받는 매크로를 사용하고, 다음에 대한 적절한 범주 코드가 적용될 때 그 매크로의 인자가 토큰화되도록 구성한다 `$` 가 작동하도록 한다.

```
\begin{document}
\def\docat{\catcode`\$=11 \getarg} % No parameters, calls a second macro \getarg
\def\getarg#1{#1} %1 parameter whose argument will be tokenized
이제 이렇게 실행하면 작동한다:

I paid \docat{$90} for that book.
\end{document}
```

우리의 새 버전의 `\docat` (예를 들어 이렇게 `\docat{$90}`)을 사용하면 그것은 *겉보기에는* 처럼 보인다 `$90` 가 여전히 다음의 인자로 사용되고 있는 듯하다 `\docat` 매크로. 그러나 앞서 논의했듯이, TeX가 다음을 감지하면 `\docat` 입력에서 그것이 인자를 가지는지 확인한다: 이제는 없으므로 TeX는 그것을 실행(확장)한다. 다음의 확장은 `\docat` 토큰들의 연속이다 `**catcode**`, ``**`**``, `**\$**`, `**=**`, `**1**`, `**1**`, `**space**`, `**getarg**` 그리고 이것은 다음 시점에 일어난다 *이전의* TeX가 입력 파일에 들어 있는 다음 문자들—즉, 그룹 `{$90}`. 기억하자: TeX가 매크로를 확장할 때 다음 입력은 그 매크로 정의의 토큰 목록에 들어 있는 토큰들을 읽음으로써 얻는다; 즉, 그 매크로의 `<대체 텍스트>` 부분에서 메모리에 저장된 것을 읽는다.

TeX는 다음의 확장을 처리하고 실행한다 `\docat` 그리고 다음을 감지한다 *토큰* **`getarg`**, 이를 매개변수를 받는 명령을 나타내는 토큰으로 인식한다. 이 시점에서 TeX는 입력 파일에서 **`getarg`**&#xC758; 인자, 즉 다음 문자들을 스캔한다: `{$90}`. 언제나 그렇듯 이것들은 토큰화되지만, TeX가 다음의 확장을 읽고 처리했기 때문에 `\docat`, 다음 문자들은 `$90` 가 토큰화될 때 `$` 의 범주 코드가 11로 바뀐 상태에서 토큰화된다. 다음의 정의(`<대체 텍스트>`)은 `\getarg` 단지 `#1` 로, 제공된 인자를 조판하라는 뜻이며, 실제로 그렇게 되어 `$` 범주 코드 11을 가진 하나의 $ 기호가 생성되고 안전하게 조판된다.

## 맺음말: 노드로 보는 이야기

다음의 재작성으로 생기는 사건의 순서는 `\docat` 매크로를 사용하도록 `\getarg` 다음 주석이 달린 노드 목록 도식에 담겨 있으며, 이 도식은 다음 매크로의 확장 과정을 보여 준다 `\docat`. 이 도식을 자세히 살펴보고 싶은 독자는 그림을 다음 형식으로 내려받을 수 있다 [PDF](https://assets.ctfassets.net/nrgyaltdicpt/7MOBdavza4WxAEQGISEEht/cabe5097d9063a6415bc553cd38237e6/newdocatexpansion.pdf) 또는 [SVG](https://images.ctfassets.net/nrgyaltdicpt/2FIqqVRXjakdAzTpZsV0m9/10ccc1353741d42d3df18f1692d8aa84/newdocatexpansion--plain.svg) 파일로 오프라인에서 사용할 수 있다.

![수정된 \docat 매크로와 \getarg 매크로를 확장하는 과정 보여 주기](/files/3dd282b708a2afaf4ab4bc9ebed1b8cddfda4d39)

[1부](/latex/ko/more-topics/19-how-tex-macros-actually-work-part-1.md) [2부](/latex/ko/more-topics/20-how-tex-macros-actually-work-part-2.md) [3부](/latex/ko/more-topics/21-how-tex-macros-actually-work-part-3.md) [4부](/latex/ko/more-topics/22-how-tex-macros-actually-work-part-4.md) [5부](/latex/ko/more-topics/23-how-tex-macros-actually-work-part-5.md) [6부](/latex/ko/more-topics/24-how-tex-macros-actually-work-part-6.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/ko/more-topics/24-how-tex-macros-actually-work-part-6.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
