# [프로그래밍 언어] 7. Implementing Subprograms

## 호출과 복귀

---

### 호출

- 매개변수 전달 방법을 포함

- 지역 변수가 정적변수가 아닌 경우

    - 지역 변수를 위한 기억 장소 할당 → 지역변수 바인딩 → 실행 상태를 저장

    - 레지스터 값, CPU 상태 비트, 환경 포인터 EP 포함

- 제어를 부프로그램 코드에 전달 → 반환

- 중첩 부프로그램 지원하면 가시적인 비지역변수를 접근할 수 있는 동작 구조를 생성

### 복귀

- 출력 모드, 입출력 모드 + 복사 매개변수 → 형식 매개변수의 지역 값을 실 매개변수로 옮김

- 기억 장소를 해제 → 실행 상태를 복원 → 제어를 호출 프로그램에 반환

## 단순 부프로그램

---

> 부프로그램의 코드 (고정크기) + 지역변수 (고정크기)

- 중첩될 수 없고 지역변수가 정적

- **호출: 실행 상태 저장 → 매개변수 계산 및 전달 → 복귀 주소 전달 → 제어 전달**

- **복귀: 실 매개변수 복사 → 함수 값 이동 → 실행 상태 복원 → 제어 전달**

**호출 복귀를 위해 저장되어야 하는 정보**

- 실행 상태

- 매개변수

- 복귀 주소

- 함수의 반환값

- 임시 기억장소

**활성화 레코드**

- 활성화 부프로그램: 실행 중인 프로그램

- 활성화 레코드: 부프로그램의 코드를 제외한 부분의 형식 → 정적

- 단순부프로그램에서 저장할 값 → 레코드 형식 구조체 필드 (인스턴스) - 데이터의 모음

**단순 부프로그램을 갖는 언어**

- 재귀 부프로그램 지원 X → 활성화된 부 프로그램은 오직 하나 → 활성화 레코드 인스턴스도 하나

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/224932_5ICKd9ERn2mozYOH6l?q=80&s=1280x180&t=outside&f=webp)

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/224943_kNTAguDdyPwoPRx4AN?q=80&s=1280x180&t=outside&f=webp)

- Local variables: 피호출

- Paramters: 호출 → 피호출

- Return address: 호출

- 호출자의 실행 상태 생략

- 함수의 반환값이 없는 경우 생략

**링커**

- 고정 크기 → 정적으로 할당

- 컴파일 시에 참조 리스트 + 기계어 코드

- 운영체제의 링커에 의해 통합

- 파일들을 메모리에 적재 → 호출 목적지 주소 설정 → 동일 작업 수행

- MAIN → 기계 코드 프로그램 + 활성화 레코드인스턴스 → 메모리 적재

- A, B, C에 대한 호출, 호출 모적지 주소 패치

## 스택-동적 지역변수 부프로그램

---

- 스택 동적 지역변수를 갖는 언어의 부프로그램 연결 구현 → 재귀 부프로그램을 지원

### **복잡한 활성화 레코드**

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/225109_DcVXbEzSEK82oFkipZ?q=80&s=1280x180&t=outside&f=webp)

- 지역변수의 묵지겅니 할당과 해제 코드 생성

- 재귀 부프로그램의 다중 동시 활성화 가능성 → 한 개 이상의 부프로그램 인스턴스가 존재

- 주어진 시점 에 한 개 이상의 부프로그램 인스턴스가 존재 → 메모리 크기에 의해 제한

- 각 활성화는 활성화 레코드 인스턴스 요구 → 컴파일 시간에 크기 및 형식 알려짐

- 피호출: Local variables

- 호출: Paramters, Dynamic link, Return address

    - return address: 다음 명령어에 대한 포인터

    - dynamic link: 호출자의 활성화 레코드 인스턴스의 기준점 base 포인터

        - 정적 영역 언어에서 추적 정보 제공 / 동적 영역 언어에서 비지역 변수 접근

    - paramters: 호출자가 제공하는 값, 주소

    - local variables: 지역 스칼라 변수 / 데이터 구조 → 힙 등 다른 곳에 할당

- 활성화 레코드 인스턴스 동적 생성 → 실행 시간 스택에 생성

**환경 포인터 EP**

- 현재 실행 중인 활성화 레코드 인스턴의 기준 주소 (실행 시간 스택에 저장 X)

- 새로운 활성화 사례에 저장 → 새로운 기준 주소를 가리키도록 설정

- 스택 꼭대기top를 재설정pop하고 동적 링크의 값으로 EP를 재설정

- g()가 실행 중이라면 f(), main은 중단중

**활성화 레코드 인스턴스 부프로그램 호출 동작**

- 활성화 레코드 인스턴스 생성 → 실행 상태 저장 → 매개변수 계산 및 전달 → 복귀 주소를 피호출 프로그램에 전달 → 제어를 피호출 프로그램에 전달

- **프롤로그 동작**: EP를 스택에 저장, 새로운 값 생성 → 지역 변수 할당

- **에필로그 동작**: 실 매개변수로 복사 → 함수 값(반환 값) 이동 → 스택 꼭대기 재설정, EP 재설정 → 실행 상태 복원 → 제어를 호출자에게 전달

### 재귀 없는 부프로그램

```javascript
void fun1(float r){
    int s, t;
    fun2(s);
}
void fun2(int x){
    int y;
    fun3(s);
}
```

```javascript
void fun3(int q){
    ...
}

void main(){
    float p;
    fun1(p);
}
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/225142_UqCmE0Bw7PVXBEFdya?q=80&s=1280x180&t=outside&f=webp)

- 함수가 시작되면 ARI 추가, 종료되면 ARI 삭제

- 동적 체인 또는 호출 체인 → 동적 링크이 집합

- 지역 오프셋: 지역 변수의 참조는 지역 영역의 오프셋 → 지역 오프셋을 EP에 더하면 찾을 수 있음

### 재귀 부프로그램

```javascript
int factorial(int n){
    // 지점 <1>
    if (n<=1) return 1;
    else      return (n*factorial(n-1));
    //지점 <2>
}
```

```javascript
void main(){
    int value;
    value = factorial(3);
    // 지점 <3>
}
```

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/225210_LBaltVMqI0tyG0BEkp?q=80&s=1280x180&t=outside&f=webp)

- 첫 번쨰 ARI는 호출자 main의 복귀 주소를 가지고 있음

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/225224_ZSu4PYeTQZqgeTUzYd?q=80&s=1280x180&t=outside&f=webp)

- 함수 값: 1 → 2 → 6

## 중첩 부프로그램

---

- Python, JavaScript, Ruby, Lua, Ada 등 → 정적 영역, 스택 동적, 부프로그램의 중첩 허용

**중첩 부프로그램 정적 영역 언어에서 비지역 변수 참조**

- 비지역적으로 접근 가능한 비정적 변수 → 활성화 레코드 인스턴스 중 하나에 존재

- 활성화 인스턴스를 찾구 → 지역 오프셋으로 변수에 접근

**정적 조상 영역의 변수에 접근**

- 자신이 정적 조상 영역에서 선언된 변수만 가시적으로 접근

- 모든 정적 조상의 활성화 레코드 인스턴스 → 스택에 항상 존재

- 모든 정적 조상 부프로그램이 활성화 → 부프로그램을 호출 가능

- 정적 조상이 활성화 상태가 아니라면 접근이 무의미

### 활성화 레코드 인스턴스 검색

**비지역 참조**

- 정확한 선언 = 첫 번째 발견된 선언

- 정적 체인을 통해 활성화 레코드 인스턴스를 찾을 수 있음

**정적 체인**

- 중첩 부프로그램을 허용하는 언어에서 정적 영역 구현

- 정적 링크 → 정적 영역 포인터 → 정적 부모의 활성화 레코드 인스턴스의 시작 주소 가리킴

- 정적 체인은 모든 정적 조상을 연결 (비지역변수를 모두 찾을 수 있음)

**단순한 방법**

- 정적 체인을 따라감

- 컴파일러는 비지역변수 참조 + 필요한 정적 체인의 길이도 알고 있음

- **정적 깊이**: 중첩되지 않은 정적 깊이는 0, A가 B 내부에 중첩되었으면 1

- **실제 참조**: (A정적 깊이 - B 정적 깊이)

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/225322_jBi2VwBvwhdwfSHcyA?q=80&s=1280x180&t=outside&f=webp)

- <1> (체인 오프셋, 지역 오프셋) = (0, 3) → 지역 변수

- <2> (2, 3) → 비지역변수 (bigsub의 변수 a)

- <3> (1, 3) → 비지역변수 (bigsub의 변수 a)

## 블록

---

```javascript
{
    int temp;
    temp = list[upper];
    list[upper] = list[lower];
    list[lower] = temp;
}
```

- 사용자-지정 지역 영역 제공

- 다른 곳에서 선언된 같은 이름을 갖는 변수에 의해 방해 받지 않음

- 블록은 프로그램의 같은 장소에서 항상 호출되는 매개변수가 없는 부프로그램을 처리

- 오프셋을 정적으로 계산하면서 블록 변수를 지역변수 인 것처럼 처리

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/225414_d88RdcgDEbnbJraQFj?q=80&s=1280x180&t=outside&f=webp)

## 동적-영역 규칙 구현

---

### 심층 접근

- 동적 영역 언어에서 지역변수가 스택 동적이고 활성화 레코드의 일부
- → 비지역변수의 참조는 가장 최근에 활성화된 부프로그램부터 시작, 인스턴스를 탐색

- 정적 체인 대신 동적 체인을 사용 → 동적 체인은 활성화된 역순으로 활성화 레코드 인스턴스 연결

- 스택 심층부에 대한 탐색 → 심층 접근

- **정적 체인과의 차이점**

    - 탐색할 체인의 길이를 결정하는 방법이 없음 → 첫 번째 인스턴스가 발견될 때까지 탐색

    - 동적영역 활성화 레코드는 변수 이름을 정해야함 → 정적 영역 언어에서는 값만 요구

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/225433_3P93FxDJ4CjORTlyah?q=80&s=1280x180&t=outside&f=webp)

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/225448_cJxtDRDlv6H68HmVR3?q=80&s=1280x180&t=outside&f=webp)

- main은 sub1 호출

- sub1은 sub2 호출

- sub2는 sub3 호출

- 변수 u 참조

- 4개의 동적 링크
- → 10개의 변수 이름 조사

- 2개의 동적 링크
- → 6개의 변수 이름 조사

### 피상 접근

- 심층 접근과 같은 목적을 달성하기 위한 다른 구현

- 활성화 레코드에 저장되지 않음

- 각 변수에 대해 별도의 스택을 만듦

- 새로운 변수가 최상위에 한 개의 셀을 할당

- 이름의 참조는 스택 꼭대기에 있는 변수 → 가장 나중에 들어간 변수(가장 최근에 생성된 변수)

- 존속시간이 끝나고 스택에서 한 항목이 제거

![Image](https://upload.cafenono.com/image/slashpagePost/20250103/225526_qQfABH5ChBowZPhY95?q=80&s=1280x180&t=outside&f=webp)

- 장점: 빠른참조 허용

- 단점: 유지보수 비용 높아짐

For the site tree, see the [root Markdown](https://slashpage.com/yerim-devnote.md).
