Chapter 01. 프로그래밍 언어부터 프로그램 실행까지, 이렇게 진행된다
- 프로그래밍 언어는 컴퓨터 과학의 작은 일부분일뿐이다.
1.1 여러분이 프로그래밍 언어를 발명한다면?
1.1.1 창세기: CPU는 똑똑한 바보
-
CPU는 단순 작업에 매우 효과적이고 빠르다.
-
그러나 초기 프로그래밍에서는 별도의 언어가 없어서 CPU의 명령어를 직접 작성해야 했다.
- 천공카드, 천공테이프, 천공테이프 리더기 등의 기계를 사용했다.
-
예시
00101001 00000000 00000000 00001000
00101001 00000000 00000000 00001000
1.1.2 어셈블리어 등장
-
이후 CPU가 수행하는 것은 결국 단순한 몇 개의 명령어라는 것을 알게 되었다.
-
이 명령어를 사람이 이해할 수 있는 언어로 변환한 것이 어셈블리어이다.
-
예시
sub $8, %rsp
mov $.LC0, %edi
call puts
mov $0, %eax
-
이러한 어셈블리어를 사용하면 CPU의 명령어를 직접 작성하는 것보다는 훨씬 편리하다.
-
그러나 이러한 어셈블리어를 바이너리로 변환하는 과정이 필요하다.
1.1.3 저수준 계층의 세부 사항 대 고수준 계층의 추상화
- 어셈블리어는 사람이 인식할 수 있지만 여전히 저수준 언어이다.
- 결국 작성자가 모든 세부 사항을 신경써야 한다.
- 이러한 어셈블리어를 추상화한 것이 고급 프로그래밍 언어이다.
1.1.4 가득한 규칙: 고급 프로그래밍 언어의 시작
- 어셈블리어로 작성하는 코드에서 특정한 패턴이 발견되었고, 이를 추상화하여 고급 프로그래밍 언어를 만들었다.
- 조건문, 반복문 및 함수 호출 등의 패턴이 추상화되었다.
1.1.5 <인셉션>과 재귀: 코드 본질
- 조건문, 반복문 등으로 구성된 코드는 여러 번 중첩 될 수 있으며, 이는 결국 재귀로 표현 할 수 있다.
- 이렇게 재귀로 표현되는 최소 단위의 표현을 구문(syntax)이라고 한다.
1.1.6 컴퓨터가 재귀를 이해하도록 만들기
- 위에서 말한 것 처럼 재귀적으로 표현되는 구문을 컴퓨터가 이해할 수 있도록 만들어야 한다.
- 이를 위해 구문을 트리 구조로 변환한다.
1.1.7 우수한 번역가: 컴파일러
- 위에서 말한 여러 과정을 처리하는 프로그램을 컴파일러라고 한다.
- 컴파일러는 작성된 코드를 파싱하여 트리 구조로 변환하고, 이를 기계어로 변환한다.
1.1.8 해석형 언어의 탄생
- 다양한 CPU의 구조를 고려하여 매번 컴파일하는 것은 매우 번거롭다.
- 이를 해결하기 위해 해석형 언어가 등장했다.
- 해석형 언어는 표준 명령어라는 중간 단계를 거쳐 CPU에 맞게 변환된다.
정리 및 과제
본인이 사용하는 언어가 코드 -> 표준 명령어 -> 인터프리터 -> CPU 과정을 어떤 식으로 수행하는지 알아보자.
- Javascript의 경우
- 렉싱 -> 파싱 -> AST -> 바이트코드 -> 인터프리터(Ignition, 빠른 실행) -> 인터프리터(TurboFan, 최적화) -> CPU