728x90
TCL 프로시져와 스코프
프로시져와 스코프
- 프로시져는 자주 사용되는 일련의 명령들을 묶어 쉽게 사용할 수 있게 함
- 각 프로시져는 변수에 대한 새로운 스코프를 가짐
- 변수의 스코프란 그 변수가 정의되는 명령의 영역을 의미
proc 명령
- TCL 프로시져를 정의하는 명령
proc name params body
- name은 프로시져의 이름, 대소문자를 구분하며 어떤 문자도 포함할 수 있다
- params는 파라미터 이름의 리스트
- 정의된 프로시져는 다른 TCL 명령과 똑같은 방식으로 사용
- 특정 값을 돌려주기 위해 return 명령을 사용할 수 있음
- default로는 마지막 명령의 결과 값이 반환됨
- 프로시져의 파라미터 이름 리스트는 기본 값을 가질 수 있음
proc p2 {a {b 7} {c -2} } {
expr $a*100+$b*10+$c
}
puts [p2 3 5 7]
#357
puts [p2 3 5]
#348
- 프로시져 p2는 1개, 2개 또는 3개의 인자로 불릴 수 있음
- 1개 호출 시 a=value1, b=7, c=-2d
- 2개 호출 시 a=value1, b=value2, c=-2
- 3개 호출 시 a=value1, b=value2, c=value3
- 프로시져는 args 키워드를 사용해 임의 개수의 파라미터를 사용하게 할 수 있음
proc argtest {a {b foo} args} {
foreach param {a b args} {
puts stdout "\t$param = [set $param]"
}
}
puts [argtest 1 2 3 4]
#a = 1
#b = 2
#args = 3 4
rename
- rename 명령은 명령어의 이름을 변경
- rename은 기존 프로시져에 기능을 추가하기 위해 사용
rename foo foo.orig
- foo 프로시져를 새로 정의할 때 foo.orig 프로시져를 호출할 수 있게 됨
- rename의 두 번째 인자로 빈 스트링을 줌으로써 명령어를 사용할 수 없게 만들 수도 있음
rename exec { }
스코프
- 변수 이름과 프로시져 이름은 다른 이름 공간을 사용하므로 같은 이름을 사용할 수 있음
- 프로시져 내에서 정의된 변수는 그 프로시져 안에서만 사용가능
- 프로시져가 리턴되면 그 변수도 소멸됨
- 프로시져 외부에서 정의된 변수는 upvar나 global을 이용해야 프로시져 내에서 사용가능
- 프로시져 외부의 이름과 일치하는 변수가 재정의되면 외부 변수는 값 변경에 영향을 받지 않음
set a 5
set b -8
proc p1 {a} {
set b 42
if {$a < 0} {
return $b
} else {
return $a
}
}
puts [p1 $b]
#42
puts [p1 [expr $a*2]]
#10
global 명령
- 프로시져 외부에서 정의된 변수를 프로시져 내부에서 사용하기 위해서 global 키워드를 이용
global varName1 varName2 ...
- global 명령은 외부 변수를 사용하고자 하는 프로시져의 내부에 포함
- 하나의 프로시져 내부에서만 유효하기에 여러 개의 프로시져에 외부 변수를 사용할 경우에는
모든 프로시져에서 global 명령을 사용해야 함
proc randomInit { seed } {
global rand
set rand(ia) 9301;# Multiplier
set rand(ic) 49297;# Constant
set rand(im) 233280;# Divisor
set rand(seed) $seed;# Last result
}
proc random {} {
global rand
set rand(seed) \
[expr ($rand(seed)*$rand(ia) +\
$rand(ic)) % $rand(im)]
return [expr $rand(seed)/double($rand(im))]
}
proc randomRange { range } {
expr int([random]*$range)
}
puts [randomInit [pid]]
puts [random]
puts [random]
puts [randomRange 100]
전역 상태 유지를 위해 배열 사용
- TCL 배열은 인덱스 값에 아무런 제한이 없기 때문에 유연하게 사용 가능
- 배열 이름에 global 명령을 사용하면 배열을 구성하는 모든 원소가 전역 변수가 됨
proc ObjInit { o x y } {
global obj
set obj($o, x) $x
set obj($o, y) $y
set obj($o, dist) [expr sqrt($x * $x + $y * $y)]
}
proc ObjMove { o dx dy } {
global obj
if ![info exists obj($o, x)] {
error "Object $o not initialized"
}
incr obj($o, x) $dx
incr obj($o, y) $dy
set obj($o, dist) [expr sqrt($obj($o, x) * $obj($o, x) + \
$obj($o, y) * $obj($o, y))]
}
upvar명령을 이용한 “Call by Name” 구현
- 프로시져에게 변수의 값이 아닌 이름을 넘겨 주고 싶을때 사용
upvar ?level? varName localVar
- level 인자는 옵션으로 기본값은 1, TCL 호출 스택의 한 단계 위를 의미
- level 인자에 숫자를 주면 그 숫자만큼 호출 스택의 단계를 넘어간 스코프를 의미
- level 인자를 #number의 형태로 주면 절대값을 가지는 특정 스코프를 의미
- #0은 global 스코프를 의미하므로 global foo는 다음 명령과 동일한 의미
upvar #0 foo foo
- 상위 단계 스택의 변수는 일반 변수, 또는 배열 변수의 원소값, 또는 배열의 이름일 수 있음
- 변수가 배열의 이름인 경우는 지역 변수가 배열로 취급
- 변수의 이름을 인자로 주었을 때 그 값을 출력하는 프로시져
proc PrintByName {varName} {
upvar $varName var
puts stdout "$varName = $var"
}
set AAA "1234"
puts [PrintByName AAA]
#AAA = 1234
- upvar 명령은 incr 명령을 개선하기 위해 사용할 수 있음
- incr 명령은 변수가 존재하지 않는 경우에 에러를 발생
- 변수가 존재하지 않는 경우 변수를 새로 생성하는 incr 프로시져
proc incr {varName {amount 1}} {
upvar $varName var
if [info exists var] {
set var [expr $var + $amount]
} else {
set var $amount
}
return $var
}
puts [incr aa]
puts [incr aa]
puts [incr aa]
#1
#2
#3
- upvar 명령을 사용한 스택 구현
proc Push { stack value } {
upvar $stack S
if ![info exists S(top)] {
set S(top) 0
}
set S($S(top)) $value
incr S(top)
}
proc Pop { stack } {
upvar $stack S
if ![info exists S(top)] {
return {}
}
if {$S(top)==0} {
return {}
} else {
incr S(top) -1
set x $S($S(top))
unset S($S(top))
return $x
}
}
puts [Push st 111]
puts [Push st 222]
puts [Push st 333]
puts [Push st 444]
puts "from here will be pop"
puts [Pop st]
puts [Pop st]
puts [Pop st]
#1
#2
#3
#4
#from here will be pop
#444
#333
#222
Global vs upvar
- global은 전역변수를 바로 이용해서 이름을 동일하게 사용하는 방법
- upvar는 call by reference 형태로 새로운 변수 이름에 연결해서 사용가능
728x90
728x90
'Programming > TclTk' 카테고리의 다른 글
TCL UNIX에서 작업하기 (0) | 2022.09.06 |
---|---|
TCL Eval (0) | 2022.09.05 |
TCL 순서제어 명령 (0) | 2022.09.02 |
TCL 자료 구조 (0) | 2022.09.02 |
TCL 스트링과 패턴 매칭 (0) | 2022.09.02 |
댓글