uplevel — 다른 스택 프레임에서 스크립트 실행하기

uplevel — 다른 스택 프레임에서 스크립트 실행하기

uplevel은 Tcl만의 독특한 능력을 가진 명령어예요. 지금 실행 중인 프로시저의 변수 문맥이 아니라, 호출 스택 위쪽에 있는 다른 프레임의 문맥에서 스크립트를 실행해줘요. 덕분에 while 같은 제어 구조를 Tcl 프로시저로 직접 구현할 수 있을 만큼 강력한 도구예요.

출처: 문서

본문

문법

uplevel ?level? arg ?arg ...?

모든 arg 인자는 concat에 전달된 것처럼 이어붙여지고, 그 결과는 level이 가리키는 변수 문맥에서 평가돼요. uplevel은 그 평가의 결과를 반환해요.

  • level이 정수이면, 명령어를 실행하기 전에 (프로시저 호출 스택 위로) 이동할 거리를 나타내요.
  • level# 뒤에 숫자가 오는 형태라면 그 숫자는 절대 레벨 번호를 나타내요.
  • level을 생략하면 기본값은 1이에요.
  • 첫 명령어 인자가 숫자나 #로 시작하면 level은 기본값으로 둘 수 없어요.

예를 들어 프로시저 a가 최상위에서 호출됐고, 그게 b를 호출했고, bc를 호출했다고 해볼게요. cuplevel 명령어를 호출한다고 가정해요.

  • level1 또는 #2이거나 생략되면 명령어는 b의 변수 문맥에서 실행돼요.
  • level2 또는 #1이면 명령어는 a의 변수 문맥에서 실행돼요.
  • level3 또는 #0이면 명령어는 최상위에서 실행돼요(전역 변수만 보임).

uplevel 명령어는 명령어가 실행되는 동안 호출한 프로시저가 프로시저 호출 스택에서 사라지게 해요. 위 예에서 c가 이 명령어를 호출한다고 해볼게요.

uplevel 1 {set x 43; d}

여기서 d는 또 다른 Tcl 프로시저예요. set 명령어는 b의 문맥에서 변수 x를 수정하고, db에서 호출된 것처럼 레벨 3에서 실행돼요. d가 다시 이 명령어를 실행하면:

uplevel {set x 42}

set 명령어는 b의 문맥에서 같은 변수 x를 수정해요. d가 실행되는 동안 프로시저 c가 호출 스택에 없는 것처럼 보이거든요. info level 명령어로 현재 프로시저의 레벨을 얻을 수 있어요.

uplevel은 새 제어 구조를 Tcl 프로시저로 구현할 수 있게 해줘요(예를 들어 while 구조를 Tcl 프로시저로 구현하는 데 uplevel을 쓸 수 있어요).

namespace evalapply 명령어는 (프로시저 호출 외에) Tcl 이름 문맥을 바꾸는 또 다른 방법을 제공해요. 이들은 네임스페이스 문맥을 나타내기 위해 스택에 호출 프레임을 추가해요. 즉 각 namespace eval 명령어는 uplevelupvar 명령어에게 또 하나의 호출 레벨로 계산돼요. 예를 들어 info level 1은 맨 바깥 프로시저 호출이거나 맨 바깥 namespace eval 명령어인 명령어를 설명하는 리스트를 반환해요. 또한 uplevel #0은 맨 바깥 네임스페이스(전역 네임스페이스)의 최상위에서 스크립트를 평가해요.

예제

앞서 말했듯 uplevel 명령어는 새 제어 구조를 만드는 데 유용해요. 이 예제는 (오류 처리는 제외하고) while의 반대편에 서는 do 명령어를 만드는 법을 보여줘요. 루프 본문을 실행한 뒤에 항상 조건을 테스트하는 것이 while과의 차이점이에요:

proc do {body while condition} {
    if {$while ne "while"} {
        error "required word missing"
    }
    set conditionCmd [list expr $condition]
    while {1} {
        uplevel 1 $body
        if {![uplevel 1 $conditionCmd]} {
            break
        }
    }
}

더 알아보기

  • apply, namespace, upvar — 문맥·네임스페이스 관련 명령어
  • 관련 키워드: context, level, namespace, stack frame, variable