CompileTime - 컴파일 단계_4
Compile
의미분석 단계
컴파일러의 컴파일 단계 중 구문분석 단계 다음에 진행하는 단계다. 구문 분석 단계에선 문법적 오류를 검출했다면, 의미 분석 단계에선 논리적 오류를 검출하는 단계이다.
예시를 들어보자,
1
int x = "asdf";
구문 분석 단계에선 이 코드를 선언문으로 인식한다.
“변수타입, 이름, 대입 연산자, 값” 으로 이루어져 있으므로, 위 코드는 문법적으로 올바른 선언문이기에 오류를 검출하지 못한다.
하지만 의미 분석 단계에선 정수형 변수 x
에 문자열 리터럴 값을 초기화 값으로 제공하는 것이 타입 불일치 오류임을 검출한다.
의미 분석 단계에서 타입 불일치를 확인할 수 있는 이유는 바로 심볼 테이블을 사용하기 때문이다.
심볼 테이블
심볼 테이블이란 프로그램의 변수, 함수, 클래스 등과 관련된 정보를 저장하고 관리하는 데이터 구조다.
심볼 테이블이 관리하는 데이터들
- 변수명
- 변수 타입
- 변수의 스코프
- 초기화 여부
- 상수 여부
- 등등
심볼 테이블을 사용하면 타입 검사 외에도 초기화되지 않은 변수 사용, 스코프를 벗어난 변수 참조, 중복 선언된 변수/함수명 등의 오류도 검출할 수 있다.
의미분석 단계 동작
이제 전체적인 의미분석 단계의 동작을 알아보자.
어휘 분석 단계는 구문 분석 단계에서 생성한 추상 구문 트리(AST)를 입력 받아 오류를 검출한다.
추상 구문 트리란?
파스 트리가 프로그램의 문법적 구조를 세부적으로 표현한 트리라면, 추상 구문 트리는 이름답게 주요 구성 요소(변수 선언, 함수 호출, 연산 등)만 남겨놓고 불필요한 문법적 세부사항들을 제거한 트리다.
1
int x = 10 + 5;
이 코드를 AST 로 표현하면
1
2
3
4
5
6
Assignment
├── Variable: x
├── Type: int
└── Expression: +
├── Literal: 10
└── Literal: 5
이렇게 표현할 수 있다.
다른 예시를 보자
1
int x = (5 + 1) * 2;
연산자의 우선순위를 위해 괄호를 추가한 식이다.
추상 구문 트리는 연산자의 우선순위를 괄호로 표현지 않고, 대신 트리의 계층 구조에 반영하는 방식을 사용한다.
1
2
3
4
5
6
7
8
VariableDeclaration
├── Variable: x
├── Type: int
└── Expression: *
├── Expression: +
│ ├── Literal: 5
│ └── Literal: 1
└── Literal: 2
때문에 의미분석 단계에선 AST 의 노드를 순회하며 순회 방식 중 일반적으로 후위 순회 방식을 사용한다.
이렇게 AST 트리를 순회하면서 발견한 변수, 함수, 클래스 등은 심볼 테이블에 업데이트되며, 타입, 스코프 정보, 초기화 여부, 상수 여부 등의 정보도 기록된다.
순회가 끝나면 분석 과정에서 발견된 오류들을 에러 메시지로 보고한다.
만약 오류가 없다면 다음 단계인 중간 코드 생성 단계로 넘어가며, 업데이트 된 심볼 테이블을 전달해준다.