Computer Science/프로그래밍언어론

[프로그래밍 언어론] 3-3. Nested Subroutines (중첩 서브루틴)

dog-pawwer 2023. 10. 15. 16:12
반응형

0. 개요

🤔 궁금증 or 들어가기 전

  우리가 프로그래밍 하면서 아주 자연스럽게 사용했던 중첩된 서브루틴에 대해 알아보자.

  중첩 subroutine 내에서 선언된 것들과 스코프 등에 대한 이야기를 해보자.

  (서브루틴 = 함수 or 메서드 정도로 생각하면 편하다)

 


1. Nested Subrotuines (중첩 서브루틴)

  •  많은 언어에서 중첩 서브루틴을 지원한다.
    ex. Algol 60, Ada, ML, Commn Lisp, Python, Scheme, Swift 등
    오히려 C언어 계열에서는 불가능

1-1. Algol 계열의 Nested Subroutines

  • 중첩 서브루틴 내에서 선언된 상수, 타입, 변수 또는 서브루틴은 해당 스코드 외부에서는 보이지 않는다. (Not-visible)
  • 이름과 객체 간의 바인딩에 대한 'the closest nested scope rule'을 만든다.

1-2. The Closet Nested Scope rule

  • 선언에서 도입된 이름은 선언된 스코프에서 알려지며,
    다른 중첩된 스코프에서 숨겨지지 않는 한 각 내부 중첩된 스코프에서 알려진다.
{ a 
   //scope1
   {    }
   //scope2
   {    }
   //scope3
   {    }  // a 가 중첩된 어디에도 없다는 가정하에
}

   위와 같이 a 는 모든 스코프 1, 2, 3에 알려진다.

   (단, 같은 이름인 a 이 중첩 스코프에서 사용되어 숨겨지는 경우 바깥쪽 a가 숨겨지게 되는 경우 제외)

  • 현재 가장 안쪽 스코프에서 해당 이름과 연결된 선언이 있는 경우! 해당 이름에 대한 활성 바인딩을 정의한다.
    그렇지 않으면 주어진 이름을 현재 가장 안쪽 스코프에서 둘러싸고 있는 스코프 및 바깥쪽으로 더 넓게 검색한다.
  • 즉, 해당 스코프에서 선언이 있다면, 그 이름과 바인딩
  • 선언이 없다면? Find -> 해당 스코프부터 프로그램의 가장 바깥 중첩 수준까지 이동하여 전역 객체가 선언된 곳까지 검색

1-3. Built-in, Predefined Object

 해석해보면, 내장 함수 혹은 이미 정의된 객체.

 이것들을 가장 바깥의 scope, 보이지 않는 추가적인 외부 scope로 볼 수 있다.

 ex. I/O 루틴, math 함수 등

2. Scope 내의 Hole

2-1. Hidden, Hole

  • 내부 서브루틴에서 선언한 name과 같은 이름의 name이 이미 외부에 선언되어 있다면,
    외부 name은 해당 scope에서 숨겨지게 된다. (Hidden)

왼쪽은 Ada or Pascal 계열 언어, 중앙은 C 계열 언어, 오른쪽은 Scop 범위

  - Ada 혹은 파스칼 언어는 선언 후 실행이 이루어진다.
    procedure 의 선언 후, 코드 가장 마지막 단에 begin과 end로 실제 실행이 이루어진다.

 

  • P3는 A1이나 X와 같은 P1에서 선언된 변수에도 접근할 수 있다.
  • P3는 P2 내부에서만 보이며 외부에서 접근할 수 없다.

 

  • P1 과 F1 모두 "X"라는 이름의 로컬 변수를 선언!
  • 중첩 서브루틴 내부의 변수 선언은 해당 스코프 내에서는 같은 이름의 외부 스코프 변수를 가리게 된다.
    => 변수 숨김으로 인한 "Hole" 발생
  • 즉, F1 내부에서 "X"를 사용하면, 내부 "X"를 참조하게 되고,
    다른 부분에서 "X"를 사용하면, 외부 "X"를 참조하게 된다.
  • -> 중첩 스코프에서 "비활성화(deactivate)"를 통해 외부 변수를 숨김으로써
    변수 이름 충돌을 방지, 중첩 서브루틴이 자체적으로 독립적인 변수를 가질 수 있도록 해준다.

2-2. 언어 별 Hole 처리

동일한 이름의 중첩된 선언으로 가려진 바인딩을 처리하는 방식은 언어별로 다르다.

 - 일반적으로는 hidden된 바인딩에 접근할 수 없도록 한다.

 - 그러나, 몇몇 언어에서는 사용할 수 있는 방법을 제공해 준다.

 

1. Ada  : '.' 사용 -> 함수명.변수명

2. C++ :  '::' 사용 -> ::변수명

 

3. Nonlocal Objects에 접근하는 방법

3-1. Local Objects(지역 변수)에 접근하는 방법

 compiler는 offeset을 사용하여 접근한다.

 실행 중 subroutine의 프레임 포인터 레지스터를 가리키도록 한다.

 

3-2. Nonocal Objects(지역 변수)에 접근하는 방법

 이론적으로는 알고 있다.

 안쪽 (해당) 스코프에서 외부 스코프로 천천히 찾아나가면서 찾아보면 된다.

 어떤 logic으로 해당 방법을 구현할 수 있을까?

 

- 가장 간단한 방법은 "static link"를 이용하는 방법

 : 이 정적 링크는 lecically surrounding subroutine의 가장 최근 호출 프레임을 가르킨다.

  = 즉, 부모 프레임을 가리키고 있다.

 

정적 링크 : 프레임들간의 정적인 계층 구조

 

 

반응형