본문 바로가기

코딩 이야기/컴파일러

컴파일러 공부하고 개발하기 #02 - 소스 코드 해석, 어휘 해석, 구문 해석, 의미 해석, 의미값

반응형

서론

 

오늘은 소스 코드 해석에 대해 다룰 것이다. 책 기준으로는 이전에 책에서 제공하는 소스코드의 간단한 일부 리뷰가 있는데, 그냥 #00과 #01 편에서 말한 순서를 코드로 나타낸 것이기에 패스하도록 하겠다. 그리고 책에서도 전처리 단계가 꽤나 복잡한 관계로 빠져버렸다.

 

소스 코드 해석에서 고려해야 할 점

 

우리가 코드가 있을 때 그냥 위에서부터 줄줄이 해석한다면 편하겠지만 우린 '연산자의 우선순위'를 고려해야 한다.

5 + 4 + 2는 컴퓨터 입장에서 (5 + 4) + 2로 받아들이게 되지만, 4 + 2 * 8은 4 + (2 * 8)로 해석해야하기에 이것이 연산자의 우선순위이다.

 

또한 함수명이 일반적으로 선언되어있는 것과 문자열 안에 함수명이 있을 때의 취급 또한 다르기에 이러한 점들을 고려해야한다.

 

 

사실 소스 코드 해석에서는 개인이 하고 싶은 방식이 있다면 그것으로 구현해도 되겠지만, 컴파일러가 오랫동안 개발되온 학문인 만큼 자주 사용되는 정석이 있어서 이 정석에 대해 다룰 것이다.

 

소스 코드 해석은 구문 해석과 의미 해석으로 나누어서 구분할 수 있고, 구문 해석은 어휘 해석과 구문 해석으로 또 상세하게 나눌 수 있다.

 

 

Lexical analyze(어휘 해석)

 

어휘 해석은 소스 코드를 단어로 분할하는 작업이다. 스캔이라고도 한다.

int main(){
	int a = 1;
	printf("Hello readers"); //안녕하세요 독자들
}

 

이런 소스 코드가 있다면

int 
main
(
)
{
int 
a 
= 
1
;
printf
(
"Hello readers"
)
;
}

이런 식으로 분할하게 된다.

티스토리 코드 블럭을 사용해서 나눠둔 것 외에 크게 차이가 없어보이지만, 공백과 줄바꿈, 주석이 사라졌다.

 

이때 우린 이 나눠둔 단어들의 종류를 추출하거나 '의미 값'을 추가한다.

 

 

단어의 Semantic value(의미값)과 종류

 

의미 해석 단계에서 단어의 종류와 의미값을 추출해야한다. 예를 들어 "100" 과 100 이 단어로 분할되어 들어왔을 때, "100"은 문자열이라는 종류와 "100" 그대로의 의미값을 가지게 되고, 100은 정수라는 종류와 숫자 100의 의미값을 가지게 된다.

 

main이나 printf, a는 함수명이나 변수명으로서 식별자라는 종류를 갖게 되고 함수명이나 변수명을 의미 값을 가진다.

 

int는 예약어이므로 int의 정보만으로도 충분히 의미를 나타낼 수 있어서 별도의 의미 값을 갖지 않는다.

 

 

Token(토큰)

 

토큰은 하나의 단어와 그 단어의 종류, 의미값을 합쳐 토큰이라고 한다.

위의 소스 코드를 해석하여 토큰화하게 되면 이런 결과가 나온다.

 

단어 종류 의미 값
int 예약어 int  
main 식별자 main
( (  
) )  
{ {  
int 예약어 int  
a 식별자 a
= =  
1 정수(int) 1
; ;  
printf 식별자 printf
( (  
"Hello readers" 문자열 "Hello readers"
) )  
; ;  
} }  


이후에 추상 구문 트리를 만들게 된다.

매우 규모가 작은 컴파일러는 구문 트리를 생성하지 않기도 한다.

 

반응형