개요
컴파일러의 중간 언어와 중간 코드 생성에 대해 알아본다. 이 글은 내공 있는 프로그래머로 길러주는 컴파일러의 이해의 내용을 기반으로 함을 미리 밝힌다. 책 내용이 괜찮으니 관심있으신 분들은 사보는것을 추천한다.(필자는 이해관계자는 아님을 밝힌다.)
목차
컴파일러 강의 다른 포스팅은 아래의 링크를 참고하자.
- 컴파일러 강의 #1, 개요
- 컴파일러 강의 #2, 형식언어와 유한 오토마타
- 컴파일러 강의 #3, 컴파일러의 어휘분석
- 컴파일러 강의 #4, 문맥자유 문법과 푸시다운 오토마타
- 컴파일러 강의 #5, 컴파일러의 구문 분석
- 컴파일러 강의 #6, 의미 분석과 형 검사
- 컴파일러 강의 #7, 중간 언어와 중간 코드 생성
- 컴파일러 강의 #8, 코드 최적화
학습목표
- 중간 언어
- 구문 지시적 번역
- 중간 코드 생성
중간 언어
-
중간 언어의 개념
- 중간코드는 구문 분석 단계에서 만들어진 구문트리를 이용하여 생성되거나, 한 문법 규칙이 감출될 때마다 구문 지시적 번역으로 생성이 이뤄진다. 중간 코드를 생성하는데는 중간언어를 사용한다.
- 중간코드는 구문 분석 단계에서 만들어진 구문트리를 이용하여 생성되거나, 한 문법 규칙이 감출될 때마다 구문 지시적 번역으로 생성이 이뤄진다. 중간 코드를 생성하는데는 중간언어를 사용한다.
-
아래와 같이 중간코드를 통해 M(전단부) * N(후단부)대신 M + N개의 컴파일러로 해결할 수 있다.
중간언어의 장단점
- 장점
- 기계 독립적인 이식성 높은 컴파일러
- 기계 독립적인 최적화
- 인터프리터를 이용하여 실행할 수 있는 장점
- 단점
- 단계가 하나 더있으므로 상대적으로 컴파일 시간이 더 소모
중간 코드를 생성하는 방법
-
중간코드 생성기
-
구문 지시적 번역
중간 언어의 종류: 후위 표기법
- 후위 표기법에
- Triple, 간접 Triple, Quadruple
- 구문 트리
-
P-코드, 바이트코드
-
후위 표기법
- 피연산자가 연산자보다 먼저 나오는 형태
- 코드를 이동할 수 없으므로 최적화에 부적합한 형태
후위표기법 예제
트리 순회 방법
- preorder
- postorder
- inorder
- 위 예제의 inorder는?
- postorder : ABC * DE / + =
- inorder : A = B * C + D / E
3-주소 코드
- 코드 재구성이 편리하여 코드 최적화에 적합
- 레지스터 기반 목적 기계코드 변환이 편리해 상용 컴파일러에서 가장 많이 사용
- 치환 연산자의 오른쪽 부분이 1개의 단항, 이항 또는 논리 연산자와 피연산자로 구성되고, 치환 연산자의 왼쪽 부분은 식별자 또는 주소를 표현하여 하나의 코드 내에서 3개의 주소를 나타내는 형식의 중간 코드
3-주소 코드 예제
3-주소 코드 표현 예제
- 3주소 코드를 실제 컴파일러에서 구현하는 방법
- Triple : 결과값을 저장하는 피연산자가 존재하지 않음
- Quadruple : 결과값을 저장하는 피연산자가 존재
- 간접 Triple : Triple에서 코드 이동시 발생하는 단점을 보완
Triple 표현 방법
간접 Triple 표현 방법
Quadruple 표현 방법
Triple/간접 Triple/Quadruple 비교
트리구조 코드
- 소스 프로그램의 의미를 보다 시각적으로 표현가능
- 코드의 특성상 손쉽게 재구성이 가능하므로 최적화 컴파일러의 IL로 가장 적합한 표현
- 트리구조 표현 방법
- 파스트리
- 구문 분석을 하는 데 시간이 많이 걸리고 메모리의 낭비를 초래한다는 것 때문에 IL로는 부적당
- 구문트리
- 파스 트리에서 의미 없는 논터미널을 제거하고 의미 있는 정보만을 트리 구조로 표현한 구문 트리(Syntax Tree)를 사용
- 구문 트리는 상수 또는 변수를 나타내는 터미널 노드와 연산자를 나타내는 논터미널 노드로 구성되며, 연산자의 피연산자들이 자식 노드로 연결되는 부분 트리를 구성
파스트리/구문트리 예제
가상 기계 코드
- 최근에는 컴파일러를 소스 언어에만 관계된 전단부와 목적 기계에만 관계된 후단부로 분리 하고, 잘 정의된 인터페이스를 사용하여 이 사이를 연결함으로 써 쉽게 이식되고 재목적이 가능한 컴파일러를 제작하는 추
- 이와 같은 방법으로 만든 컴파일러를 재목적 컴파일러(retargetable compiler)라 하는데, 컴파일러를 한 기계에서 다른 기계로 이식하는 문제를 이렇게 후단부만 변경함으로써 쉽게 해결
P-코드
- p-코드는 컴퓨터에 별도의 컴파일러가 없어도 p-코드 인터프리터만 있으면 프로그램을 간단히 실행시킬 수 있다. 하지만 목적 코드로 번역되는 한 단계가 추가되므로 실행 시간이 느리다는 것이 단점
바이트코드
- 바이트코드는 이기종 간의 실행 환경에 적합하도록 설계되어 이식성과 유연성이 좋고, 인터프리터 방식과 JIT( just-in-time) 컴파일러 방식에 의해 실행
구문 지시적 번역
- 각 생성규칙에 해당하는 의미 수행코드를 직접 기술
- 변수값 계산, 중간코드 생성, 에러 메세지 출력, 기호표 삽입
- 의미수행코드
- 예를 들아 다음과 같은 생성 규칙과 의미규칙이 있다고 가정하자
- $ E -> E_1 + E_2$, {$E.VAL = E_1.VAL + E_2.VAL$ }
- 중괄호전은 생성 규칙
- 중괄호 뒤는 의미 규칙
구문 지시적 번역기의 구현
- 감축이 발생할 때 감축되는 생성규칙의 오른쪽 문법기호에 대해 스택에 나타나는 속성을 가지고 새로운 합성 속성 값을 계산
- 상향식 구문 분석기는 구문 분석된 부분트리에 대한 정보 저장을 위해 스택을 사용
- ABC가 X로 감축 될 때 C.VAL는 VAL[TOP], B.VAL는 VAL[TOP-1], A.VAL는 VAL[TOP-2]에 있다. 감축이 일어난 후 TOP이 2만큼 감소하고, VAL[TOP]은 X.VAL의 값을 갖게 된다.
주석 파스트리 예제
구문 지시적 번역기 예제
중간코드 생성방법
- 구문 분석 과정에서 중간코드 생성
- 구문 에러시 코드생성이 무의미하므로 시간낭비 초래
- 구현이 복잡함
- 구문 에러가 없는 경우 빠르게 중간코드 생성 가능
- 중간 표현을 생성 후 중간코드 생성
- 중간 코드 생성에 필요한 정보만 저장하고 있으므로 코드 생성기 구현이 용이
- 컴파일러 크기가 커지고 컴파일 시간이 길어짐
중간코드 생성
백패칭
테스트
중간 언어란?
중간코드는 구문 분석 단계에서 만들어진 구문트리를 이용하여 생성되거나, 한 문법 규칙이 감출될 때마다 구문 지시적 번역으로 생성이 이뤄진다. 중간 코드를 생성하는데는 중간언어를 사용한다.
중간언어의 장단점
- 장점
- 이식성 높은 컴파일러
- 기계 독립적인 최적화
- 인터프리터 사용 가능성
- 단점
- 컴파일 시간이 추가로 필요하고 비효율적인 목적 기계 코드가 생성됨
후위 표기법, 3주소코드, p-코드, 바이트 코드의 특징
C := (B * A) + D를 3-주소 코드, triple, 간접 triple, quadruple로 나타내시오
A. 3주소 코드 표현
T1 = B * A
T2 = T1 + D
C = T2
B. Triple 표현
번호 | OP | 피연산자1 | 피연산자2 |
---|---|---|---|
[0] | * | B | A |
[1] | + | [0] | D |
[2] | = | C | [1] |
C. 간접 Triple 표현
수행순서 |
---|
[0] |
[1] |
[2] |
번호 | OP | 피연산자1 | 피연산자2 |
---|---|---|---|
[0] | * | B | A |
[1] | + | [0] | D |
[2] | = | C | [1] |
D. Quadruple
번호 | OP | 피연산자1 | 피연산자2 | 결과 |
---|---|---|---|---|
[0] | * | B | A | T1 |
[1] | + | T1 | D | T2 |
[2] | = | T2 | C |
다음 식을 triple, 간접 triple, quadruple로 바꾸시오
코드는 아래와 같음
번호 | Triple | 간접 Triple | Quadruple |
---|---|---|---|
[0] | *,C,D | *,C,D | *,C,D,T1 |
[1] | /,[0],E | /,[0],E | /,T1,E,T2 |
[2] | +,B,[1] | +,B,[1] | +,B,T2,T3 |
[3] | -,[2],F | -,[2],F | -,T3,F,T4 |
[4] | =,A,[3] | =,A,[3] | =,T4,A |
[5] | *,C,D | =,G,[1] | *,C,D,T5 |
[6] | /,[5],E | /,T5,E,T6 | |
[7] | =,G,[6] | =,T6,G |