본문 바로가기
프로그래밍언어론

[프로그래밍언어론] 13. 가시성 규칙(Visibility Rules), 범위 규칙(Scope Rules)

by 파스텔코랄 2023. 10. 10.

가시성 규칙(Visibility Rules)

  • 비공식적인 개념이다.
  • 이름의 가시성을 결정하고 특정 블록에서 어떤 바인딩을 사용할 수 있는지 결정하는 규칙.
    • 블록의 로컬 선언은 해당 블록과 해당 블록 내의 다른 모든 블록에 표시된다.
    • 블록에 동일한 이름의 새 선언이 있는 경우 이 새 선언은 이전 선언을 숨긴다.

 

0: { int a = 1;
    1: { int b = 2;
        2: { int b = 3;
                int c = a + b;
                printf("%d\n", c);
            }
        3: { int d = a + b;
                printf("%d\n", d);
            }
        }
    }
  • 블록 0~3이 있다.
  • 현재 블록이 변경되면 환경도 변경된다.
  • 따라서 동일한 이름이 다른 개체에 연결될 수 있다.
  • 변수 c의 값 : 4
  • 변수 d의 값 : 3
    • 먼저 블록 0a가 선언되어 있으므로 블록  0~3 모두에서 볼 수 있다.
    • 첫 번째 b블록 1에서 선언되므로 블록 1, 2, 3에서 볼 수 있다.
    • 두 번째 b블록 2에서 선언되며 블록 2에서만 볼 수 있다.
    • 블록 2의 첫 번째 b를 숨기므로 블록 2에서 b는 항상 두 번째 b를 나타낸다.
    • 반면, 블록 3에서는 두 번째 b(블록 2의)가 표시되지 않는다.
    • 블록 1의 첫 번째 b블록 3에서 볼 수 있으므로 d를 계산하는 데 사용된다.
    • 따라서 c는 4이고 d는 3이다.

 


 

환경

  • 위의 예시에서 변수 a가 글로벌 변수라고 가정해보자.
  • 그러면 a는 모든 블록에 표시되며 글로벌 환경의 일부가 된다.
  • 블록 1의 경우 a의 바인딩은 글로벌 환경이자 비로컬 환경이다.
  • 로컬 환경의 이름은 내부 블록에 표시된다.
  • 로컬 환경의 이름은 외부 블록에 표시되지 않는다.
  • 로컬이 아닌 환경의 이름은 로컬 환경의 동일한 이름으로 숨겨진다.
  • 예) 블록 2의 로컬 환경에서 첫 번째 b의 바인딩이 비활성화된다.

 


 

그래도 이것만으로는 부족하다.

  • 우리가 논의한 가시성 규칙은 대략적인 큰 그림을 설명한다.
  • 구체적이고 세부적인 규칙은 언어마다 다를 수 있다.
  • 예를 들어 방금 설명한 경우는 Java에서는 유효하지 않다.
  • 이전 예제는 C로 작성되었으며 오류 없이 작동한다.
  • Java에서는 로컬변수 중복이 허용되지 않는다.
  • 반면에 전역 변수를 재정의할 수 있다.
  • 그러므로 우리는 각 프로그래밍 언어에 대한 구체적인 규칙을 이해해야 한다.
0: { int a = 1;
    1: { int b = 2;
        2: { int b = 3;             // 오류가 발생
                int c = a + b;
                printf("%d\n", c);
            }
        3: { int d = a + b;
                printf("%d\n", d);
            }
        }
    }

 


 

범위 규칙(Scope Rules)

  • 블록과 관련된 다양한 환경에서 이름이 표시되는 방식을 대략적으로 설명한다.
  • 본 포스트에서는 정적동적 관점에 대해 다룬다.

 


 

정적 vs. 동적

  • 정적 범위 : 프로그램 자체의 구문 구조에만 의존
    • 따라서 환경은 컴파일러에 의해 완전히 결정될 수 있다.
  • 동적 범위 : 프로그램의 역방향 실행을 사용하여 바인딩을 결정
    • 따라서 런타임 중에 결정될 수 있다.

 


 

정적 범위 규칙

  • 정적 범위 규칙은 가장 가까운 중첩 범위의 규칙으로 간주될 수 있다.
  • 세 가지 규칙
    • 규칙 1. 블록에 대한 로컬 선언은 해당 블록의 로컬 환경을 정의
    • 규칙 2. 이름이 블록 내에서 사용되는 경우 이 이름의 유효한 바인딩은 로컬 환경에 존재.
      존재하지 않는 경우 가장 가까운 외부 블록에 존재
    • 규칙 3. 블록 자체는 이름과 연관될 수 있으며 이러한 이름은 블록의 로컬 환경의 일부이다.

 


 

규칙 1. 지역 선언

  • 지역적으로 선언된 변수는 지역 환경을 정의한다.
  • 블록 1의 경우 이 블록에는 변수 b만 선언된다.
  • 다른 변수는 표시되지 않거나 표시되지만 로컬 환경에는 포함되지 않는다.


 

규칙 2. 가장 가까운 중첩 범위

  • 변수 a블록 3에서 참조된다.
  • 단, 이 블록에는 a가 선언되지 않는다.
  • 규칙 2에 따라 블록 1을 먼저 검색한다.
  • 아직 찾을 수 없으므로 블록 0을 시도한다. → a가 여기에 선언되어 있다.
  • 블록 2는 "중첩된" 블록만 검색하므로 건너뛰었다.

 


 

규칙 3: 블록에 할당된 이름

  • Java 코드에서 메소드 이름 put, 매개변수 list, str는 실제로 블록 내부에 없다.
  • 단, 로컬 환경에서는 사용 가능하다.
  • 또한 로컬 환경의 일부이므로 외부 블록에는 표시되지 않는다.
    • put()은 선언이 포함된 블록에 표시되는 프로시저이기 때문에 예외이다.
public static void put(List<String> list, String str) {
	list.set(list.size()/2, str);
}

 


 

정적 범위의 장점

  • 이러한 모든 정적 범위 규칙은 미리 정의되어 있으며 코드의 구문 구조에만 의존한다.
  • 컴파일러는 사용된 이름의 모든 바인딩을 추론할 수 있다.
  • 이 사실은 큰 이점을 제공한다.
    • 프로그램에 대해 더 잘 이해할 수 있다.
    • 컴파일러는 정확성 테스트를 수행할 수 있다.
    • 컴파일러는 상당한 최적화를 수행할 수 있다.

 


 

동적 범위

  • 프로그램의 특정 지점 P에서 이름 X의 유효한 바인딩,
    • 가장 최근에 생성된 바인딩 X 이다.
  • X는 P 지점에서 계속 활성화되어 있어야 한다.
Shell Script

1:   x=1
2:   function foo() {
3:       echo $x;
4:       x=2;
5:   }
6:   function bar() {
7:       local x=3;
8:       foo;
9:   }
10: bar
11: echo $x
  • 정적 범위를 사용하는 경우
    • 1행의 x는 전역 변수
    • 함수 bar은 라인 10에서 호출
    • 내부에서 foo를 호출
    • foo 함수는 3행에서 1을 인쇄 → 1행의 x를 사용
    • 그런 다음 x는 11번 라인에서 다시 인쇄 → x는 4번 라인에서 변경
      • 따라서 2를 인쇄

 

  • 동적 범위를 사용하는 경우 이 스크립트의 실제 출력
    • 3(3번째 줄에 인쇄)
      1(11번째 줄에 인쇄)
  • 3행에서 이름 x의 가장 최근 바인딩은 7행에 있다.
    • 따라서 3이 인쇄
  • 11번째 줄에서 x의 가장 최근 바인딩(4번째 줄의 2)이 이미 사라졌다.
  • 따라서 1이 인쇄

 


 

동적 범위의 장점

  • 프로그램을 다시 작성하지 않고 프로그램의 동작을 더 쉽게 수정할 수 있다.
  • 실제로 정적 범위 규칙 OOP를 사용하여 언어로 비슷한 작업을 수행할 수 있다.
    • 데코레이터 패턴
  • 그러나 코드를 쉽게 이해하기 어렵다.
코드 작성

function pizza() {
    echo "A pizza $toppings"
    toppings=""
}
function cheese() {
    toppings="$toppings+cheese"
}
function peperoni() {
    toppings="$toppings+peperoni"
}


코드 실행, 런타임 명령

#cheese pizza
cheese
pizza

#peperoni pizza
peperoni
pizza

#double cheese pizza
cheese
cheese
pizza
실행 결과

A pizza +cheese
A pizza +peperoni
A pizza +cheese+cheese









댓글