[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5. 조건, 루프, 재귀

일반적인 텍스트로 확장된, 인자를 가지는 매크로는 아마도 충분히 만족스럽지 는 않을 것이다. 여기에 또다른 매크로를 확장하는 여러것들이 있다. 이것들은 실 행시에 결정된다. 예를 들면 일반적으로 조건문이 필요할 것이다. 또한 몇가지의 루프를 만드는 것도 있으면 좋을 것이다. 따라서 여기서는 여러번 어떤 일을 한 다던지, 아니면 주어진 조건이 참인지 검사하는 것들을 소개할 것이다.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1 매크로 정의 테스트

m4에는 두 개의 다른 내장 조건문을 제어하는 것이 있다. 첫번째는 ifdef이다.

 
ifdef(name, string-1, opt string-2)

이것은 매크로가 이미 정의가 되었는지 그렇지 않은지 테스트 하는 것이다. name이 정의된 매크로의 명칭이라면 ifdefstring-1으로 확장되고, 아니면 string-2로 확장된다. string-2를 생략한다면, 그것은 일반적인 규칙을 따라서 빈 문자열이 된다.

 
ifdef(`foo', ``foo' is defined', ``foo' is not defined')
⇒foo is not defined
define(`foo', `')
⇒
ifdef(`foo', ``foo' is defined', ``foo' is not defined')
⇒foo is defined

ifdef 매크로는 단지 인자가 있을 때에만 인식된다.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2 문자열 비교


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3 문자열 비교

다른 조건을 제어하는 것은 ifelse인데, 이것은 훨씬 강력하다. ifelse 는 긴 주 석을 만든다던지, 또는 일반적인 if-else 와 같이 사용할 수도 있고 여러개로 가 지를 뻗을 수 있다. 이것은 전적으로 제공되는 인자의 개수에 의존한다.

 
ifelse(comment)
ifelse(string-1, string-2, equal, opt not-equal)
ifelse(string-1, string-2, equal, ...)

하나의 인자만으로 ifelse를 사용한다면, ifelse 는 그 인자를 취소하며, 아무런 출력도 하지 않는다. 이것은 주석을 블록단위로 만들 때 사용하는 m4의 공통적인 관습이다. dnl을 사용하면 출력되는 빈공백을 없앨 수 있다. 이런 특별한 사용 법은 GNU m4가 인식한다. 이 경우에 있어서 인자와 관련된 에러 경고는 결코 트리거되지 않는다.

세 개나 네 개의 인자로 호출한다면 ifelsestring-1string-2가 같을 경우 (문자대 문자)는 equal로 확장되고 다른 경우는 not-equal로 확장된다.

 
ifelse(foo, bar, `true')
⇒
ifelse(foo, foo, `true')
⇒true
ifelse(foo, bar, `true', `false')
⇒false
ifelse(foo, foo, `true', `false')
⇒true

ifelse 는 네 개보다 더 많은 인자를 가질 수 있다. 네 개보다 많은 인자가 주어 진다면 ifelsecaseswitch 구문과 같은 전통적인 프로그래밍 언어와 같이 작동한다. string-1string-2가 같다면 ifelseequal로 확장되고 다른 경우는 첫 세 개의 인자는 건너뛰고 다시 되풀이 한다. 여기에 간단한 예가 있다.

 
ifelse(foo, bar, `third', gnu, gnats, `sixth', `seventh')
⇒seventh

보통의 평범한 경우는 위의 예제보다는 좀더 복잡한 양상을 띄게 될 것이다. ifelse의 공통된 사용은 다양한 종류의 루프용 매크로 도구로 사용하는 것이다.

ifelse 매크로는 인자가 있을 때에만 인식된다.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4 루프와 재귀

m4 에서 적접적인 루프는 제공하지 않는다. 하지만 매크로는 재귀적으로 될 수 있다. 재귀적 표현의 단계는 제한이 없다. 여러분의 하드웨어나 운영체제에 의해 제한되는 것은 제외하고는...

루프는 재귀적으로 프로그래밍 될 수 있으며 조건문은 앞서와 같이 사용할 수 있다.

shift라는 내장 매크로가 있는 데 이것은 매크로에서 활성화된 인자들을 되풀 이 하는 데 사용된다.

 
shift(...)

괄호안에는 어떠한 개수의 인자도 올수 있으며, 첫 번째 인자를 제외하고는 모 두 확장된다. 확장될 때는 따옴표 처리된 인자 단위로 되고 쉼표로 분리된다.

 
shift(bar)
⇒
shift(foo, bar, baz)
⇒bar,baz

다음의 매크로는 shift의 예인 데, 여기서는 각각의 인자의 순서로 거꾸로 만 들고 있다.

 
define(`reverse', `ifelse($#, 0, , $#, 1, ``$1'',
`reverse(shift($@)), `$1'')')
⇒
reverse
⇒
reverse(foo)
⇒foo
reverse(foo, bar, gnats, and gnus)
⇒and gnus, gnats, bar, foo

별로 흥미있는 예는 아니지만, 위의 것은 shiftifelse로 간단한 재귀적 루프를 만들 수 있다는 것을 보여준다.

이제 루프 매크로 forloop 을 사용하는 간단한 예제를 보자. 예에서 보는 바와 같이 이것은 간단한 숫자세기를 한다.

 
forloop(`i', 1, 8, `i ')
⇒1 2 3 4 5 6 7 8

인자는 차례대로 반복될 변수명, 처음 가지는 값, 마지막 값, 매회 확장될 텍스 트 이다. 여기에서 매크로 i는 단지 루프내부에서만 정의된다. 루프가 끝난 후에 는 이전에 가졌던 값을 그대로 유지한다.

For-loop 는 또다시 내장될 수 있다. 다음과 같이

 
forloop(`i', 1, 4, `forloop(`j', 1, 8, `(i, j) ')
')
⇒(1, 1) (1, 2) (1, 3) (1, 4) (1, 5) (1, 6) (1, 7) (1, 8)
⇒(2, 1) (2, 2) (2, 3) (2, 4) (2, 5) (2, 6) (2, 7) (2, 8)
⇒(3, 1) (3, 2) (3, 3) (3, 4) (3, 5) (3, 6) (3, 7) (3, 8)
⇒(4, 1) (4, 2) (4, 3) (4, 4) (4, 5) (4, 6) (4, 7) (4, 8)
⇒

forloop 매크로는 그것자체로 충분히 멋이 있으며 간단한 독립적인 모듈이다. 그리고 처음에 호출하면 먼저 첫 번째 인자의 이전 정의를 저장하고 내부 매크로 _forloop 을 호출한다. 그리고 저장된 첫 번째 인자 정의를 복구한다.

_forloop 매크로는 한 번에 4개의 인자로 확장하며 끝이 났는가를 알아보기 위 해 테스트 한다. 만일 끝이 나지 않았다면 변수의 값을 이미 정의된 매크로인 incr을 사용하여 하나 증가시키고 다시 재귀적으로 실행된다. (incr은 see section 증가, 감소 연산자.)

여기에 forloop를 정의한 유용한 매크로가 있다.

 
define(`forloop',
`pushdef(`$1', `$2')_forloop(`$1', `$2', `$3', `$4')popdef(`$1')')
define(`_forloop',
`$4`'ifelse($1, `$3', ,
`define(`$1', incr($1))_forloop(`$1', `$2', `$3', `$4')')')

따옴표를 사용할 때 조심하여야 한다. 세 번째 인자만이 따옴표가 없는 데, 각 각은 그것 자체의 이유가 있다. 세 번째 인자가 따옴표가 없는 지를 알려면, 따옴표로 묶었을 때 어떤 일이 일어나는 지를 살펴보면 된다.

이제, 두 개의 유용한 매크로를 살펴보았다. 아마도 그래도 이것으로는 일반적 인 사용에는 뭔가 조금 허전함을 느낄 것이다. 위의 두가지 매크로에서 시작값이 종료값보다 클 경우라던지, 첫 번째 인자가 명칭이 아니라던지 하는 경우의 기본 적인 에러를 처리하는 부분이 조금 미약하다. 이러한 에러를 바로 하는 것은 독 자 여러분의 연습문제로 남겨둔다.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Autobuild on June 20, 2017 using texi2html 1.82.