KTUGFaq

KTUG FAQ

로그인:
비밀번호:
가입
You will soon meet a person who will play an important role in your life.
FrontPage › LittleTree/ReadingTeXbook/2006-08
Aug 29, 2006
The @ convention
Submitted by 작은나무 @ 08-29 [10:32 pm]
TeXbyTopic에 쓰여져 있기를,

Anyone who has ever browsed through either the plain format or the LaTeX format will have noticed that a lot of control sequences contain an 'at' sign: @. These are control sequences that are meant to be inaccessible to the ordinary user.

Near the beginning of the format files the instruction
\catcode‘@=11
occurs, making the at sign into a letter, meaning that it can be used in control sequences. Somewhere near the end of the format definition the at sign is made 'other' again:
\catcode‘@=12
Now why is it that users cannot call a control sequence with an at sign directly, although they can call macros that contain lots of those 'at-definitions'? The reason is that the control sequences containing an @ are internalized by TeX at definition time, after which they are a token, not a string of characters. Macro expansion then just inserts such tokens, and at that time the category codes of the constituent characters do not matter any more.

TeXbook이 말하기를,

\uppercase의 진실
Submitted by 작은나무 @ 08-29 [11:16 am]
텍이 사용하는 256개의 문자들 각각은 \uccode, \lccode라 불리는 두개의 값을 가지고 있습니다. 그리고 그 두개의 값은 \catcode에 의해서 그 문자의 catcode가 바뀌는 것처럼 \uppercase 혹은 \lowercase에 의해서 \uccode, \lccode의 값을 변경시킬 수 있습니다.

문자는 (문자코드, 카테고리코드)의 쌍으로 이루어져 있다고 합니다. 예를들어 소문자 알파벳 "b"의 문자코드 98이고 카테고리코드는 11입니다. b=(98,11). 그리고 INITEX이 시작할때, 알파벳 대소문자 52자를 제외하고는 \uccode 와 \lccode의 값은 모두 0입니다. a~z와 A~Z의 \uccode는 A~Z이고, \lccode는 a~z입니다.

\uppercase가 하는 일은 주어진 문자토큰의 문자코드를 그 문자코드의 \uccode 값으로 바꾸는 일을 합니다. 예를들면, 소문자 b=(문자코드, 카테고리코드)=(98, 11)입니다. 그런데 \uppercase{b} 하면 b의 문자코드가 b의 \uccode인 B로 바뀌므로 (66,11)이 되고 따라서 대문자 B로 보이게 됩니다.

여기서 눈여겨 봐야 할 것은 \uppercase에 의해서 문자의 문자코드만 바뀌었지, 카테고리코드는 바뀌지 않는다는 것을 알 수 있습니다. 이러한 특성을 이용하면 대단히 재미있는 것을 할 수 있습니다.
\uccode`1=`b \uppercase{1}
위에서 "1"의 \uccode를 "b"로 했습니다. 따라서 \uppercase{1} 하면 "b"가 되는데, 재미있는 것은 위 과정을 통해서 만들어진, 우리 눈에 보이는 소문자 "b"의 카테고리코드는 11이 아닌, 원래 "1"의 그것인 12라는 점입니다.
{\uccode‘1=‘i \uccode‘2=‘f \uppercase{\gdef\if@12{} }} % ‘if’ is required
위 과정을 통해서 우리눈에 보이는 \if@if 에서 뒤의 "if"의 카테고리코드는 12가 됩니다. 왜냐하면 숫자 1과 2의 카테고리코드가 12이기 때문입니다. 그렇다면 위에서 정의한 \if@ 매크로가 하는 일은 카테고리코드 12인 문자 "if"를 잡아먹는 일을 합니다. 그렇다면, 이제는 모든 것이 명확해 졌습니다.
\def\@if#1#2{\csname\expandafter\if@\string#1#2\endcsname}
위에서 #1을 \iffoo, #2를 true라고 합시다. 그러면 \string\iffoo에 의해서 \,i,f,f,o,o의 카테고리코드가 모두 12가 되고, 더구나 \newif 매크로의 첫부분에 \escapechar=-1에 의해서 "\"는 출력되지 않습니다. 따라서 "\@if \iffoo true"는 "\csname footrue \endcsname"이 되는 것입니다. \if@ 가 \ 가 빠진 iffoo에서 앞의 if를 먹어버렸습니다. 그래서 footrue만 남았습니다. 그리고 "\csname footrue \endcsname"는 \footrue와 똑같은 것이지요. 이제 \newif 매크로를 다시 한번 살펴보세요. ^^

이상의 내용은 TeXbyTopic의 13.6절에서 한 수 배운 내용입니다. 텍북에서 막히는 것은 텍바이토픽이 너무도 명확하고 간결하게 해결해줍니다. 정말 멋진 책이 아닐 수 없습니다. 훌륭한 책 덕분에 궁금증을 너무 쉽게 해결한 것 같아서 좀 아쉽기는 합니다.

이해 못해, 이해 못해~~~
Submitted by 작은나무 @ 08-29 [09:42 am]
348쪽: 우리가 자신만의 조건문을 만들기 위해서 사용하는 \newif 라는 명령어가 있습니다. 이 놈은 특이하게도 한 큐에 세개의 명령어(?)를 만들어 줍니다. 예를 들어 "\newif\iffoo" 라고 하면,
   \footrue, \foofalse, \iffoo
위와 같은 것들이 만들어집니다. 각각이 뭐 하는 놈들인지는 이름을 보면 대충 알겠습니다.

그래서 \newif 라는 놈이 신기해 보여서 어떻게 정의되어 있길래 그런가 하고, 매크로 정의를 찾아보았습니다.
\outer\def\newif#1{\count@=\escapechar \escapechar=-1 \expandafter\expandafter\expandafter \def\@if#1{true}{\let#1=\iftrue}% \expandafter\expandafter\expandafter \def\@if#1{false}{\let#1=\iffalse}% \@if#1{false}\escapechar=\count@} % the condition starts out false \def\@if#1#2{\csname\expandafter\if@\string#1#2\endcsname} {\uccode‘1=‘i \uccode‘2=‘f \uppercase{\gdef\if@12{} }} % ‘if’ is required
일단 우리는 "@", "\expandafter", "\csname \endcsname" 이런거 나오면 일단 쫍니다. ^^ 그래도 그동안 공부해 둔 것이 있어서 차근차근 읽어 보았습니다. 그럭저럭 감탄도 해가며, "이렇게 하는거구나" 하고 거의 감을 잡았습니다. 하지만 도저히 이해 못할 것이 하나 있습니다. 바로 맨 마지막 줄.
{\uccode‘1=‘i \uccode‘2=‘f \uppercase{\gdef\if@12{} }} % ‘if’ is required
도대체 왜 "\uccode"라는 것을 이용해서 어렵게 "\if@if"라는 매크로를 정의 했는지는 도무지 이해 못하겠습니다. 그냥
\def\if@if{}
라고 하면 안되는 것인지. 무슨 이유로 그룹을 하나 만들고, 그 그룹안에서 \uccode를 변경하고 \uppercase를 통해서 그걸 원하는대로 돌려놓고, 그룹안에서 정의했기때문에 \gdef를 사용하고... 분명 무슨 이유가 있을텐데...쩝

이해할 날을 기대하며, 오늘도 텍 공부를 합니다. ^^

Aug 29, 2006
우리의 지식이 쬐끔 부족해서 복잡해 보일 뿐입니다.
Submitted by 작은나무 @ 08-29 [12:36 am]
375쪽: 보기에 복잡하고 어렵게 보인다고, 지레 겁먹을 필요가 없습니다. 알고 보면 별거 아닌게 많습니다. 우리에게 생소하게 보이는게 많아서 어려워 보일지도 모르겠습니다. 하지만, 공부를 통해서 생소하게 보이던 것이 익숙해지면, 그 어렵게만 느껴지던 것들이 아주 쉽게 보입니다. (당연한 얘기지만.) 공부하는 재미가 바로 그런게 아닌가 합니다.

\t는 토큰 리스트 레지스터인데, 약간의 텍스트로 이루어져 있다고 합시다. (텍에서 토큰이 뭔지, 레지스터가 뭔지 모르시는 분은 공부하셔야 합니다. ^^ ) 예를 들면 다음과 같은 것이지요.
\newtoks\t \t={Once upon a time there lived ...}
이때, \t를 이루고 있는 그 텍스트에 적어도 하나의 별표(*)가 있는지 확인하는 방법이 여러가지가 있겠지만, 그 중하나는 다음과 같습니다.
\newif\ifresult % for the result of a computed test \def\atest#1{\expandafter\a\the#1*\atest\a} \long\def\a#1*#2#3\a{\ifx\atest#2\resultfalse\else\resulttrue\fi}
위와 같이 매크로를 정의하고 "\atest\t"라고 하면 \t 에 별표가 있는지에 여부에 따라 \ifresult의 값이 결정이 됩니다. 동작하는 원리를 알아보시겠습니까? 예전에 작은나무가 열심히 올렸던 \expandafter와 그 밖의 처음보는 명령어들을 공부하시면, 아무것도 아니라는 것을 아시게 될것입니다. 파일의 맨 처음에 \tracingmacros=2와 \tracingcommands=2 라고 해 놓으시면, 위 매크로들의 동작 원리를 더욱 쉽게 파악 할 수 있을 것입니다.

다음과 같은 좀 더 엘레강스한 방법도 있습니다.
\def\btest#1{\expandafter\b\the#1*\bb} \long\def\b#1*{\futurelet\next\bb} \long\def\bb#1\bb{\ifx\bb\next\resultfalse\else\resulttrue\fi}
위 두가지 해결책 모두 \t에 문자 토큰이 아닌 명령어 토큰(control sequence token)들이 있어도 동작합니다. 단, \atest, \a, \bb 만 빼고.

Aug 28, 2006
"왼쪽 괄호를 구분자로 사용하기"
Submitted by 작은나무 @ 08-28 [12:25 am]
204쪽: 텍에서 매크로를 정의하는 방식은 다음과 같습니다.
\def<명령어><파라미터 텍스트>{<치환 텍스트>}
<파라미터 텍스트>의 맨 마지막 문자가 "#"가 올 수 있는데, 즉, # 다음에 왼쪽 괄호 "{"가 곧바로 오는 경우인데, 이때 텍은 마치 <파라미터 텍스트>와 <치환 텍스트> 오른쪽 맨끝에 "{"가 있는 것처럼 행동을 합니다. 이렇게 함으로써 매크로가 확장될 때, 각 파라미터의 구분자로 사용된 문자들을 없어지는데 "#{" 에서 "{"는 없어지지 않습니다. 예를들어, 다음과 같은 매크로 정의가 있다고 합시다.
\def\foo #1:#2{[#1] #2}
위의 정의에서 구분자 ":"는 \foo 매크로의 두 개의 파라미터를 구분하기 위해서 사용되는 것으로 <치환 테스트>에서는 사용되지 않습니다. 즉 <치환 텍스트>에서 ":"를 명시적으로 사용하지 않는 이상, 구분자로 사용된 ":"는 없어집니다. 정리하면 "#{"를 이용하면 "{"를 파라미터 텍스트에서 사용할 수 있고, 파라미터의 구분자(delimiter)로 사용할 수 있습니다. 그럼 "#{"가 사용되는 예를 들어 봅시다.
\def\a#1#{\hbox to #1}
위 처럼 정의된 매크로 \a가 "\a3pt{x}"라고 사용되면 이 것은 "\hbox to 3pt{x}"로 전개됩니다. 위의 정의에서 <파라미터 텍스트>의 맨마지막에 "#"가 사용되었으므로 \a의 첫번째 파라미터 #1은 \a 와 { 사이에 있는 "3pt"가 됩니다. 그래서 "\hbox to 3pt{x}"로 전개되는 것입니다. 또 다른 예로, 매크로 \a 를 정의하는데, \a{...}를 전개하면 \b{...} 가 되게끔하고 싶습니다 어떻게 하면 될까요? 매크로 \a를 다음과 같이 정의하면 됩니다.
\def\a#{\b}
마지막으로 재미있는 예를 들어보겠습니다. 플레인 텍에는 \bf 라는 명령어가 있는데, 이는
{\bf 어쩌구 저쩌구...}
처럼 사용되며, "어쩌구 저쩌구..."를 굵은글꼴(boldface)로 바꿉니다. 그런데 위 처럼 {\bf ...}로 사용하는게 아니라 \bold{...}로 사용하고 싶습니다. 어떻게 하면 될까요? 여러가지 방법이 있을 수 있습니다. 난이도 순으로 살펴보면 다음과 같은 방법이 있다고 합니다.
  1. \def\bold#1{{\bf #1}}
  2. \long\def\bold#1{{\bf #1}}
  3. \def\beginbold{\bgroup\bf} \def\endbold{\egroup}
  4. \def\bold{\bgroup\bf\let\next=}
  5. \def\bold#{\bgroup\bf\let\next= }
4, 5번을 마지막을 유심히 살펴보세요. 참 기발한 방법입니다. "\let\next=" 를 이용해서 { 를 없애는 방법은 익혀 둘 만합니다. 사실 이 방법은 \aftergroup을 이야기할 때에도 나왔던 방법입니다.

Aug 26, 2006
\aftergroup
Submitted by 작은나무 @ 08-26 [11:08 pm]
279쪽: \aftergroup는 그다지 익숙한 명령어는 아닙니다. 그래서 그 사용 빈도 또한 매우 낮습니다. \aftergroup은 \afterassignment와 비슷한 형식을 가지고 있습니다.
\aftergroup<토큰>
\aftergroup은 그 다음에 나오는 <토큰>을 일단 저장해 두었다가 현재 사용되고 있는 그룹이 끝난 다음에 <토큰>이 사용됩니다. 예를 들면,
\def\abc{\catcode... \xyz}
\def\xyz#1{...}
...
\abc{argument}
위의 예에서 알 수 있듯이 argument는 \catcode에 의해서 어떤 catcode들이 변경 된 다음에 \xyz의 인자로 사용됩니다. 위의 예는 \aftergroup을 사용하면 다음과 같이 됩니다.
\def\abc{\catcode... \bgroup\aftergroup\xyz\let\dummy=}
...
\abc{...}
\bgroup으로 일단 그룹이 시작되고, \aftergroup에 의해서 \xyz가 저장됩니다. 그리고 \bgroup에 의해서 시작된 그룹이 끝난 다음에 \xyz가 사용됩니다. 잘 살펴볼 것은 \let에 의해서 \abc의 왼쪽 괄호 "{"가 흡수된다는 것입니다. 따라서 \abc가 하는 일은 먼저 catcode들을 변경 시키고, 그룹을 시작하고, \xyz를 저장하고 "{"를 흡수하고 인자들을 읽어 들이고 마지막으로 그룹을 닫습니다. 그리고 나서 매크로 \xyz가 전개되는 것입니다.

\afterassignment
Submitted by 작은나무 @ 08-26 [11:00 am]
279쪽: \afterassignment를 같이 공부해 보겠습니다. \afterassignment는 다음과 같은 형태로 사용됩니다.
\afterassignment <토큰> <assignment문>
위에서 <assignment문>은 "할당문" 혹은 "대입문" 이라고 번역된 것을 보았는데, 예를들면 다음과 같은 것들입니다.
\baselineskip=12pt
\parskip=0pt plus 1pt
\abc=10
...
위에서 "=" 은 생략 할 수 있습니다.

\afterassignment는 이렇습니다. 우선 바로 뒤에 나오는 <토큰>을 잘 저장해 두었다가, <토큰>뒤에 나오는 <assignment문>을 실행한 후에 저장해 두었던 <토큰>을 뒤이어 나올 입력에 추가하는 것입니다. 말만 들어서는 뭘하는 놈인지 잘 모르겠습니다. 예를들어, 다음과 같은 매크로를 생각해 보겠습니다.
\def\abc#1{\leftskip=#1 \rightskip=#1}
이 매크로는 문단의 모양을 정하는 매크로 일텐데, 다음과 같이 사용해야 합니다.
\abc{4pt plus 5pt minus 4pt}
큰 문제는 없습니다만, 보기에 약간 어색합니다. 왜냐하면 위에서 예를들었지만, 다음과 같은 식으로 사용을 하지,
\parskip 0pt plus 1pt
아래와 같은 식로 사용하지 않기때문입니다.
\parskip{0pt plus 1pt}
위에서 정의한 매크로를 \abc 4pt plus 5pt minus 4pt 처럼 사용하면 원하는 바를 얻을 수 없는 이유를 한번 생각해 보시기 바랍니다.

바로 위의 예와 같은 경우에 \afterassignment를 사용해서 해결 할 수 있습니다.
\def\abc{\afterassignment\aux \skip0=} \def\aux{\leftskip=\skip0 \rightskip=\skip0}
위의 \abc가 전개될때, 먼저 주어진 입력에서 \skip0에 할당할 수 있는 최대 길이의 입력 스트링을 받아들여서 \skip0에 할당합니다. 그리고 나서 \aux가 전개되므로 아무런 문제가 없습니다. 사실 우리가 잘 알고 있는 매크로, \hglue, \vglue, \openup, \magnification 같은 매크로가 \afterassignment를 이용해서 정의되었다고 합니다.

숫자에 콤마 넣기
Submitted by 작은나무 @ 08-26 [09:28 am]
작은나무가 즐겨 사용하는 매트로 \fifo ... \ofif를 이용해서 주어진 숫자에 콤마(,) 넣는 매크로 \insertcommas를 만들어 보았습니다. 어디에 어떤 버그가 숨어있고, 쓸데없는 부분이 있을지도 모르겠습니다. 슬슬 텍 공부를 다시 시작하려는데, 오랜만에 하려니 잘 안되네요. ^^

\def\fifo#1{\ifx\ofif#1\ofif\fi \process#1\fifo} \def\ofif#1\fifo{\fi} \newcount\n \newcount\m \def\insertcommas#1{\n=0 \def\process##1{\advance\n1 }\fifo#1\ofif \m=\n \divide\n3 \advance\n1 \multiply\n3 \advance\n by-\m \ifnum\n=3 \n=0 \fi \advance\n-1 \def\process##1{\advance\n1 \ifnum\n=3 {,}\n=0 \fi ##1} \fifo#1\ofif}

다음과 같이 입력하면,
\insertcommas{1}
\insertcommas{12}
\insertcommas{123}
\insertcommas{1234}
\insertcommas{12345}
\insertcommas{123456}
\insertcommas{1234567}
...

아래와 같은 결과를 얻을 수 있습니다.



Aug 23, 2006
INITEX
Submitted by 작은나무 @ 08-23 [12:08 pm]
39쪽: TeX 에는 INITEX 이라 불리는 프로그램이 있는데, 이 녀석은 TeX 설치할 때 사용되는 놈이라네요. 그것도 아주 밑바닥 부터. 아마도 TeX을 만드는 프로그램인가 봅니다. TeX을 만드는 TeX이라 이름이 INITEX 인것 같고, 이 놈은 우리에게 친숙한 TeX 보다 몇 가지 일을 더 하는 것을 빼고는 그다지 특별한 프로그램은 아니랍니다. 그 더하는 몇 가지 일이란,
  • 하이프네이션 패턴을 압축된 형태로 TeX의 특수 용도 테이블에 잘 보관하는 일. 그렇게함으로써 우리가 실제로 TeX을 사용해서 조판을 할때는 하이프테이션을 좀 더 빨리 수행할 수 있도록 해준다네요.
  • plain TeX인 경우, plain.tex 으로 부터 포멧 파일인 plain.fmt 을 만든다고 일.
이처럼 TeX이 하는 일보다 몇가지 더 일을 하니까, 일할 때 메모리가 더 필요하겠지요. 그래서 이 용도로 메모리를 더 사용하기 때문에, 조판을 위한 메모리는 그만큼 줄어든다고 하네요. (그런데 INITEX으로 조판을 할 일이 있기는 있나요? ^^)

당연한 얘기겠지만, INITEX은 그 이름에서도 추측할 수 있듯이, 텍에 대해서 아무것도 모르고 오로지 텍의 프리미티브 밖에 모른다고 합니다. 그래서 모든 문자의 카테고리도 정해주어야 하고, 여러가지 필요한 것들을 만들고 정해주어야 한다네요. 그러한 일들을 plain 텍에서는 plain.tex가 하지요. 그렇다면 다른 모든 텍에도, 예를들면, 레이텍도 알고 보면 INITEX 에게 레이텍을 레이텍 처럼 만들게 해주는 무슨 파일이 있을거라고 추측할 수 있겠지요?

^
Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2006-08-29 22:32:07
Processing time 7.3421 sec