본문으로 바로가기

Tcl의 프로시져

category 카테고리 없음 2024. 4. 18. 10:53

프로시져(procedure)는 인자를 지정할 수 있는 함수입니다. 또한 자주 사용되는 커맨드를 조합한 함수라고도 할 수 있습니다. 프로시져는 Tcl 커맨드와 동일한 동작을 하기 때문에, Tcl 커맨드와 마찬가지로 동일하게 사용하실 수 있습니다.

프로시져 이름 규칙은 아래와 같습니다.

  • 영 대/소문자를 구분합니다.
  • 어떤 문자라도 사용할 수 있습니다.
  • 변수명과 같은 이름도 가능합니다.

프로시져의 인자와 리턴

아래는 프로시져의 예입니다. max 프로시져는, 인자로 주어진 두 값 중 큰 값을 리턴합니다.

proc max {a b} {
        if {$a > $b} {
                return $a
        } else {
                return $b
        }
}
max 10 20
=> 20
max 20 10
=> 20

 

인자는 리스트 형식으로 열거합니다. return 커맨드는, 프로시져로부터 값을 돌려줄 때 사용합니다. 아래의 예는 주어진 3개의 평균값을 리턴합니다.

proc average {a b c} {
        set sum [expr $a + $b + $c]
        expr $sum / 3
}
average 10 20 30
=> 20

 

set 커맨드로 작성한 변수 sum은, 프로시져 밖에서 참조할 수 없는 지역변수입니다. 여기서는 return 커맨드를 사용하지 않았지만, 프로시져 안에서 마지막으로 실행한 커맨드의 결과는 프로시져의 리턴값이 되므로, return은 생략 가능합니다.

인자가 없는 프로시져

아래의 예는 프로시져에 인자가 없는 경우입니다.

proc getdate {} {
        set sec [clock seconds]
        clock format $sec -format "%Y/%m/%d"
}
getdate
=> 2008/04/06

글로벌(global) 변수의 참조

프로시져 안에서 글로벌 변수를 참조하고자 한다면, global 선언을 할 필요가 있습니다. 아래의 예는, Tcl 버전을 체크하여 국제화에 대응된 버전인지 아닌지를 검사합니다.

proc isI18N {} {
        global tcl_version
        expr $tcl_version > 8.0
}
isI18N
=> 1

 

Tcl8.0 이상에서는, global 커맨드를 사용하지 않아도 스코프 연산자(::)를 사용하여 글로벌 변수를 참조할 수 있습니다.

proc isI18N {} {
        expr $::tcl_version > 8.0
}
isI18N
=> 1

가변 인자

프로시져에 가변개의 인자를 주는 것도 가능합니다. 마지막 인자에 args를 사용하면 리스트의 형태로 취급할 수 있습니다. 아래의 예는 주어진 가변개의 인자 값의 합을 계산합니다.

proc sum {args} {
        set sum 0
        foreach num $args {
                incr sum $num
        }
        return $sum
}
sum 1 2 3
=> 6
sum 1 2 3 4
=> 10

디폴트(default) 인자

인자에 기본 값을 지정한 것으로, 프로시져를 호출 시 가장자리로부터 인자를 생략할 수 있습니다. 아래의 예는 주어진 두 개의 인자값의 합을 계산합니다. 두 번째 인자를 생략하면 1로 지정됩니다.

proc add {a {b 1}} {
        expr $a + $b
}
add 10
=> 11
add 10 2
=> 12

인자의 참조

인자에 값을 건네주는 대신, 변수명을 건네줄 수 있다면 요긴하게 사용될 수 있을 것입니다. 예를 들면, 배열 변수는 값으로 건네줄 수 없으므로, 배열 변수명으로 건네주어 값을 참조할 수 있습니다. 아래의 예는, 배열 변수 ary의 이름을 건네주고 있습니다.

set ary(이름) 민인학
set ary(세) 31세
set ary(성별) 남
proc getname {a} {
        upvar $a var
        return $var(이름)
}
getname ary
=> 민인학

 

upvar는 변수명의 참조(별명)를 작성합니다.

 

또, 인자에 변수명을 건네줌으로, 변수의 값이 직접 변경됩니다. 아래의 예에서는, 첫 번째 인자로 주었던 변수의 값이 변경됨을 확인할 수 있습니다.

proc add {a {b 1}} {
        upvar $a var
        set var [expr $var + 1]
}
set a 1
add a
=> 2
set a
=> 2

global과 upvar 그리고 uplevel

출처: http://terzeron.net/wp/?p=244

프로시져 내부로 제어가 넘어가면 기본적으로는 외부나 상위의 프로시져의 변수를 사용할 수 없습니다. 매번 매개변수를 사용할 수는 없는 노릇이므로 global이나 upvar를 사용하여 상위레벨의 변수에 접근하게 됩니다. global 명령은 외부의 변수들을 전역변수로 지정하여 현재 프로시져 내부에서 지역변수처럼 자연스럽게 사용할 수 있게 합니다. upvar는 Tcl의 참조에 의한 호출 (call-by-reference)을 지원하기 위해 사용되는 명령으로 상위레벨의 프로시져에서 사용되는 변수를 새로운 이름으로 지정해서 지역변수로 사용하게 합니다.

set virtual_average 30.0
proc average parameters {
        global virtual_average
        set sum 0.0
        foreach i $parameters {
                set sum [expr $sum + $i]
        }
        return [expr $virtual_average + $sum / [llength $parameters]]
}


이 예제는 평균을 구하는 위의 예제에 가평균을 사용하기 위해 약간 손을 본 프러시져입니다. virtual_average가 외부에서 정의되었기 때문에 proc average에서는 사용할 수가 없어서 global 명령으로 virtual_average를 지역변수 화한 것입니다. 다음의 예는 upvar를 이용해서 새로운 지역변수로 상위레벨의 변수를 참조하는 것을 보이는 것입니다.

proc print array_name {
        upvar $array_name arr
        foreach item [lsort $arr] {
                puts $item
        }
}


upvar는 정수값을 이용해서 참조의 대상이 되는 변수를 어느 레벨까지 찾을 것인가를 결정할 수 있는데, #0을 쓰면 무한대로 거슬러 상위로 올라갈 수 있습니다. 다음의 예는 바로 상위의 프로시져의 array_name이나 혹은 그 프로시져를 호출한 더 상위의 프로시져에서 사용된 array_name을 arr로 참조하겠다는 의미입니다. 그다음 줄은 상위로 계속 거슬러 올라가면서 array_name이라는 변수를 찾겠다는 의미입니다.

upvar 2 $array_name arr
upvar #0 $array_name arr


upvar와 비슷한 명령으로 uplevel이라는 명령이 제공되는데, 이 명령은 eval과 upvar를 합쳐놓은 기능을 합니다. 다음 명령이 프러시져 내부에서 사용되면 이 프러시져를 호출한 프러시져의 x변수를 참조해다가 43을 대입하는 것을 실행할 수 있게 합니다.

uplevel 1 {set x 43}