유효범위 규칙
변수를 선언할 때에도 유효범위 규칙이 적용되었다. 선언된 이름(식별자)의 유효범위는 선언된 이름이 유효한 프로그램의 범위, 영역을 의미한다. 변수 이름 이외에 함수 이름에도 유효 범위가 있다. 유효 범위를 정하는 규칙에는 정적 유효범위 규칙과 동적 유효범위 규칙이 있다. 정적 유효범위 규칙은 선언된 이름은 선언된 블록 내에서만 유효하다는 것이며, 동적 유효범위 규칙에서는 선언된 이름은 선언된 블록의 실행이 끝날 때 까지 유효하며 실행 경로에 따라 유효범위가 달라질 수 있다.
int x = 0;
fun void g(int y)
x = x + y * y;
fun void f(int z)
let int x = 10; in
g(z);
print x;
end;
f(5);
print x;
위 코드에서 정적 유효범위 규칙과 동적 유효범위 규칙을 적용해 보자. 먼저 정적 유효범위 규칙을 적용하면, f(5)가 호출되고 f(5) 함수 내에서 선언한 변수 x의 값은 10이 된다. 그리고 g(z) 함수가 실행되는데 z 값은 5이므로 g(5) 함수가 실행된다. g 함수 내의 x는 Line 1에서 선언한 값 변수 x이므로 g(5) 함수를 통해 Line 1의 x 값이 25가 된다. 그리고 함수가 종료되고 다시 f(5) 함수로 돌아와 print x를 실행하는데, 정적 유효범위 규칙에 따라 선언된 이름은 선언된 블록 내에서만 유효하므로, f(5) 함수에서 변수 x는 10의 값으로 선언되었으므로 f(5)에서 x의 값을 print하면 10의 값이 출력된다. 이후 마지막 줄의 print x 문장을 통해 Line 1의 x 값이 출력되는데 앞서 g(5) 함수 실행으로 Line 1의 x에 25의 값이 저장되었으므로 25가 출력된다. 따라서 정적 유효범위 규칙에서는 10, 25의 값이 차례로 출력된다.
해당 블록이 실행 중이라면, 해당 변수가 유효한 동적 유효범위 규칙을 적용해보자. f(5) 함수가 실행되고, 함수 f 내의 x가 10의 값을 가지고 g(5) 함수가 실행된다. 따라서 g(5) 함수에서 x의 값은 10 + 5 * 5 = 35가 된다. 이후 함수 g의 실행이 끝나 print x 문장을 통해 35의 값이 출력되고 함수 f의 실행이 종료된다. 이제 함수 f가 실행이 종료되었으므로 유효한 변수는 Line 1의 x 뿐이다. 따라서 마지막 print 문이 실행되면 0의 값이 출력된다. 따라서 동적 유효범위 규칙을 적용하면 35, 0의 값을 순서대로 출력한다.
바인딩, 심볼 테이블
바인딩(binding)이란 이름을 어떤 속성과 연관짓는 것으로 보통 변수, 상수, 함수 등의 이름(식별자)을 속성과 연관짓는 것을 말한다. 다음은 바인딩의 에시이다.
- 이름 상수의 실제 상수 값 정하기
- 변수 / 함수의 유효범위 또는 타입 정하기
- 변수의 메모리 주소 정하기
- 연산 기호가 나타내는 실제 연산을 정하는 것
- 함수 호출과 호출된 함수를 연관짓는 것
이와 같은 바인딩은 타입 검사와 마찬가지로 바인딩을 하는 시간에 따라 정적 바인딩, 동적 바인딩으로 구분한다. 정적 바인딩은 컴파일 시에 1번 바인딩을 하고, 실행 동안 변하지 않고 유지된다. 동적 바인딩은 실행 중 이루어지는 바인딩으로 실행 중간에도 속성이 변경될 수 있다.
바인딩은 속성을 연관짓는 것이라 하였는데, 연관지은 속성 정보를 관리해야 한다. 이 속성 정보의 관리를 심볼 테이블에 유지 관리하여 유효한 속성 정보를 관리할 수 있다. 인터프리터는 변수의 이름을 변수 타입, 유효범위, 값, 위치 등을 심볼 테이블에 유지관리하고, 함수 이름의 경우 함수 타입, 유효범위, 코드 위치 등을 유지관리한다. 보통 심볼 테이블은 스택 형태로 구현된다.
함수의 타입 규칙
함수의 타입 검사를 해보자. 함수의 선언에서 함수가 bool 값을 리턴하기로 했는데 함수 body에서 int 타입 값을 반환한다면 타입 오류가 발생할 것이다. 따라서 함수 헤더에 선언한 리턴 타입과 일치하는 타입의 값을 반환해야 한다. 함수 정의를 위한 타입 규칙은 다음과 같이 정의한다. 즉, 함수는 함수 헤더에 선언된 것처럼 정의되어야 한다. fun t2 f(t1 id) S와 같이 함수를 선언하였다면, T[id |-> t1] |- S:t2 -> T |- fun t2 f(t1 id) S: t1 -> t2이다. 여기서 id는 매개변수이며, 매개변수로 선언된 id의 타입 t1 정보를 타입 환경 T에 추가하고, 이 환경에서 함수 본체 S가 t2 타입의 값을 반환하는지 검사하는 것이다. 이 검사를 통과하면 이 함수는 올바르게 정의된 것이며, 이 정의된 함수의 타입은 t1 -> t2가 된다.
함수 정의를 위한 타입 규칙을 알아보았으니, 함수 호출의 타입 규칙에 대해 알아보자.
1. 호출된 함수는 유효한 함수 이름이어야 함
2. 함수 호출에서 인자는 선언된 함수의 매개변수 타입과 같아야 한다.
3. 함수 호출의 결과 값의 타입은 함수의 리턴 타입이 된다.
이것은 함수 이름 f가 타입 환경에 있는 유효한 함수 이름인지 먼저 검사하고, 그 타입 정보(t -> t')를 이용해 함수 호출에서 사용되는 인자가 대응되는 매개변수가 같은 타입인지 검사하며, 이 조건이 만족되면 함수 호출의 결과는 t' 타입이 된다. 이를 다음과 같이표현할 수 있다. p: T(f) = t -> t', T |- E: t, q: T |- f(E): t'. p -> q.
설명이 장황하지만 간단하다. 정수 타입 매개변수 하나를 값으로 받아 제곱한 값을 리턴하는 함수 fun을 정의하였다고 가정하자. 이 함수를 사용할 때 funtion(3)와 같이 사용하면 타입 환경에 존재하는 유효한 함수 이름이 아니므로 타입 오류가 발생하므로 fun(3)과 같이 사용해야 한다. fun(3.14)로 사용하면 어떻게 될까? 함수 정의에서 매개변수는 정수 타입이므로 이 역시 타입 에러가 발생하므로 매개변수로 정수 변수를 사용해야 한다. 이와 같이 우리가 함수 정의, 함수 호출에서 기본적으로 지키는 규칙만 지키면 타입 에러가 발생할 일은 없다. 이와 같이 함수와 관련된 여러가지 정보를 알아보았다.
'CS > 프로그래밍 언어론' 카테고리의 다른 글
[프로그래밍 언어론] 객체지향 언어 (0) | 2025.07.07 |
---|---|
[프로그래밍 언어론] 예외의 처리 (0) | 2025.07.07 |
[프로그래밍 언어론] 함수와 매개변수 전달 (0) | 2025.07.04 |
[프로그래밍 언어론] 타입 시스템 (0) | 2025.07.04 |
[프로그래밍 언어론] 타입과 언어의 분류 (0) | 2025.07.03 |