CS/컴파일러

[컴파일러 이론] 7. Semantic Analysis

CSE 2025. 12. 25. 14:30

lexical analysis와 syntax analysis를 통과했다고 그 코드가 멀쩡한 것은 아니다.

 

예를 들면,

a=3; 이런 코드는 문법상 문제가 없지만 이전에 a가 선언되지 않았다면 에러가 발생해야한다.

또는 함수이름은 func(0);처럼 사용해야하지만 func=0;이라고 사용하는 에러도 있을 수 있다.

문법상 func도 변수의 이름이 될 수 있기 때문에 이전 단계에서는 탐지할 수 없기 때문이다.

 

어쩃든 이제 이런 의미적인 부분을 따지는 Semantic Analysis를 알아보자.

 


Semantic Analysis

Semantic Analysis에는 크게 두 종류가 있다.

 

1. 범위(scope)와 관련된 분석

2. 타입(type)과 관련된 분석


Scope

코딩을 하면서 기본적으로 알고 있던 scope의 개념과 똑같다.

컴파일러는 내부적으로 어떤 변수가 어떤 scope에서 선언되었는지, type은 어떤지를 저장하기 위해 symbol table을 사용한다.

 

위 그림처럼 계층 구조를 사용하게 되면 같은 변수 이름을 사용해 충돌이 나는 문제도 해결이 된다.

예를 들어 현재 f.1 scope에 있다고 가정하고 x라는 변수를 만났을 때 이 x는 어디에 속하는 변수인지를 알아보자.

당연히 현재 scope에 x가 선언 되어있는지 살펴본다. 이 경우 바로 현재 scope에서 찾았으므로 여기서 탐색을 멈춘다.

만약 현재 scope에 없었다고 한다면 계층 구조를 하나씩 올라가면서 x를 찾는다.

 

물론 이 scope와 관련된 우선순위 또는 규정들은 언어마다 조금씩 다르다.

 


type

이제 타입과 관련된 분석을 알아보자.

 

integer와 string 타입을 서로 더할 수 없고, integer와 float를 더하면 결과는 float가 되는 것과 같은 내용들을 다룬다.

 

아래처럼 두 피연산자의 타입을 보고 결과로 나오는 변수의 타입을 정할 수 있다.

 

 

여러 변수 또는 표현식의 경우 복잡해질 수 있기 때문에 이를 위해 inference rule이라는 것이 있다.

 

x : T  이 표현은 x가 타입T를 가진다는 것을 나타낸 것이다.

일반적으로 inference rule에서는 아래와 같은 형식을 사용한다.

 

예시로 아래처럼 작성할 수 있다.

즉 e1이 int고 e2가 int라면 둘을 더한 값도 int라는 것이다.

이번에는 약간 더 어려운 예시를 보자.

아래의 경우 if가 참이던 거짓이던 e2또는 e3가 결과가 될 것이고 둘의 타입은 모두 T이므로 if문의 타입은 T가 된다.

 

 

하지만 if e1 then e2 라는 식의 경우 어떻게 해야할까?

이 때는 false일 때 타입이 애매해진다.

이 경우 그냥 void 타입을 사용하기로 한다.

 

한 inference rule의 결과를 다른 inference rule에 계속 사용하므로써 더 복잡한 식의 타입도 결정할 수 있다.


Static Scoping과 Dynamic Scoping

 

아래 그림에서 func1()이 반환하는 값은 무엇일까?

생각하기에 따라서 10이 될 수도, 50이 될 수도 있다.

Static Scoping에서는 symbol table을 사용해 결정하고, 따라서 global에 있는 x의 값을 사용한다.

 

Dynamic Scoping에서는 call stack를 사용해 결정한다.

즉 가장 최근에 선언된 함수를 바탕으로 변수 값을 정한다.

위 예시의 경우 func2호출 전 func1이 호출 되었으므로 그 안의 값이 x의 값으로 사용된다.

언어마다 다른 scoping방법을 선택해 적용한다.