컴퓨터는 const a = 10;을 읽을 수 없다.
컴퓨터는 0과 1밖에 이해하지 못하기 때문이다.
나는 0과 1로만 작성된 코드를 읽을 수 없다.
나는 컴퓨터가 아니기 때문이다.
따라서, 둘을 연결하는 중간다리 역할이 필요하며, 이것이 컴파일러의 역할이다.
저급언어와 고급언어
컴퓨터는 0과 1밖에 이해하지 못한다.
기계는 일반적으로 저급 언어를 사용하며 0과 1로 구성된 기계어도 저급 언어 중 하나다.
인간이 0과 1로만 프로그래밍 하는것은 불가능에 가깝다.
이를 해결하기 위해 조금이라도 개선한 언어가 "어셈블리어"이다.
하지만, 어셈블리어도 우리가 이해하기에는 여전히 어렵다.
따라서, 이러한 단점을 보완하기 위해 인간의 가독성을 우선으로 여긴 언어들이 등장했으며 이를 고급 언어라 부른다.
고급 언어의 예시로는 JavaScript, Python, Java 등 우리가 알고 있는 대부분의 프로그래밍 언어이다.
컴파일과 인터프리터
컴파일은 전체 코드를 한 번에 기계어로 번역하는 것이다. 그와 반대로 인터프리터는 언어의 코드를 한 줄씩 입력 받아서 번역과 동시에 실행시킨다.
인터프리터를 사용하는 언어는 대표적으로 Python와 JavaScript가 있다.
인터프리터는 컴파일에 비해 프로그램의 수정이 쉽다는 장점이 있지만, 프로그램을 실행하기 전에는 어떤 문제가 발생할지 모른다는 문제가 있다.
컴파일 과정
컴파일은 크게 어휘 분석, 구문 분석, 중간 코드 생성, 코드 최적화, 목적 코드 생성의 순서로 이루어진다.
어휘 분석
어휘 분석 단계에서는 입력으로 들어오는 소스 코드를 읽어 "토큰"을 생성하는 역할을 한다.
const a = 10; const b = 20;과 같은 입력이 들어올 때, 이를 [const, a, =, 10, ;, const, b, =, 20, ;]과 같이 의미를 갖는 최소한의 단위로 쪼갠다.
구문 분석
구문 분석기는 "파서(Parse)"라고도 불린다.
어휘 분석 단계에서 생성된 토큰들을 입력으로 받아 코드의 구조를 나타내는 트리를 생성한다.
이렇게 나타내는 트리의 종류에는 Parse Tree, AST가 있다.
중간 코드 생성
파서에서 출력된 트리를 바탕으로 변수의 타입 등을 검사하고 중간 코드를 생성한다.
이러한 중간코드의 예시로는 Java 바이트 코드(JVM에서 실행되는 명령어의 형태) 등이 있다.
중간 코드를 생성하는 이유는 언어와 기계 사이의 의존성을 독립적으로 유지하기 위해서다.
만약, 소스 코드를 바로 기계어로 번역한다면 해당 컴파일러는 해당 기계에서 특정한 언어만 인식할 수 있는 컴파일러가 될 것이다.
코드 최적화
중간 코드를 바탕으로 비효율적인 코드를 찾아 코드 최적화를 진행한다.
로컬 최적화와 전역 최적화로 나뉜다.
로컬 최적화는 다시 상수 연산(a = 2 + 3을 a = 5로 치환), 상수 전파(a = 5, b = a + 5를 a = 5, b = 10으로 치환), 불필요한 로드와 중복을 제거 등을 수행하고,
전역 최적화 단계에서는 공통 부분식 축약, 반복문 내에서 값이 변하지 않는 코드를 밖으로 이동, 도달할 수 없는 코드 삭제 등을 진행한다.
목적 코드 생성
최적화 된 중간 코드를 바탕으로 목적 기계에서 동작하는 코드를 생성한다.
참고자료
컴파일러는 어떻게 내가 작성한 코드를 인식하는걸까? - 재그지그의 개발 블로그 (wormwlrm.github.io)
'개발 > 개념' 카테고리의 다른 글
[객체지향] SOLID 예제(3) - 개방-폐쇄의 원칙(OCP) (0) | 2023.09.26 |
---|---|
[객체지향] SOLID 예제(2) - 의존성 역전의 원칙(DIP) (0) | 2023.09.25 |
[객체지향] SOLID 예제(1) - 단일 책임의 원칙(SRP) (0) | 2023.09.25 |
[CS: 운영체제] 프로세스 메모리 구조 (0) | 2023.07.15 |
React에 TypeScript 사용하는 방법 (0) | 2022.08.31 |