중첩 서브프로그램과 정적 체인

함수 안의 함수가 바깥 함수의 변수를 쓰면, 그 칸은 어떻게 찾을까?

중첩 서브프로그램

함수 안에 함수

함수 안에 함수를 정의한 것을 중첩 서브프로그램(nested subprogram)이라고 합니다. 정적 스코프에서는 안쪽 함수가 자기를 둘러싼 바깥 함수의 변수를 쓸 수 있습니다.

이 강의가 따르는 교재의 자바스크립트 예제입니다. var는 변수 선언이고, sub2(x)의 x는 main의 x와 다른 변수입니다. 정적 스코프는 코드에 적힌 구조로 변수를 찾는 규칙입니다(4강).

실행하면

스택에는 부른 순서대로 쌓입니다

main이 bigsub를, bigsub가 sub2를, sub2가 sub3을, sub3이 sub1을 부릅니다. 스택에는 부른 순서대로 쌓이고, 맨 위의 sub1이 a = b + c를 실행합니다.

인스턴스(호출 한 번의 칸 묶음)를 상자 하나로 줄여 그렸습니다.

잘못된 길

부른 쪽으로 가면 엉뚱한 c

sub1이 쓰는 c는 코드에서 sub1을 둘러싼 bigsub의 c입니다. 그런데 동적 링크를 따라가면 sub3이 먼저 나오고, sub3에도 c가 있습니다. 동적 링크는 부른 순서일 뿐, 코드의 구조가 아닙니다.

정적 링크

둘러싼 쪽을 가리키는 화살표

그래서 인스턴스마다 칸을 하나 더 둡니다. 정적 링크(static link)입니다. 코드에서 자기를 바로 둘러싼 함수(정적 부모)의 인스턴스를 가리킵니다.

sub3은 sub2 안에 정의돼 있어, sub3의 정적 링크는 sub2를 가리킵니다.

정적 체인과 정적 깊이

몇 겹 안쪽인지 셉니다

정적 링크를 이은 사슬이 정적 체인(static chain)입니다. 함수가 몇 겹 안쪽에 있는지를 나타내는 수가 정적 깊이(static depth)이고, 가장 바깥이 0입니다.

체인 오프셋

깊이의 차이만큼 건너갑니다

쓰는 곳의 정적 깊이에서 그 변수가 선언된 곳의 정적 깊이를 뺀 값이 체인 오프셋(chain offset)입니다. 둘 다 코드에서 정해지므로 컴파일러가 실행 전에 계산해 둡니다.

컴파일러는 소스 코드를 기계어로 번역하는 프로그램입니다.

쌍으로 적는다

(몇 번 건너가, 몇 칸 위)

변수 하나는 체인 오프셋과 지역 오프셋의 쌍으로 적습니다. b는 (1, 4)입니다. 정적 링크를 한 번 건너 bigsub의 인스턴스로 가서, 바닥에서 4칸 위를 읽습니다. c는 (1, 5)입니다.

a는 sub1 자기 변수라 건너가지 않고 3번 칸, 곧 (0, 3)입니다. 0~2번은 반환 주소, 정적 링크, 동적 링크라서 첫 변수가 3번입니다.

다음 편

이 정적 링크는 누가 이어 줄까요

8편정적 링크는 누가 이어 줄까? 9강 목록