𝝅번째 알파카의 개발 낙서장

screen

Compiler(컴파일러) & Interpreter(인터프리터)

posts

CS

count

컴파일러와 인터프리터 🔗

천공카드 이래로 지금까지 컴퓨터 언어는 무수히 많은 발전을 거듭했다. 현재에 이르러서는 개발된 언어끼리의 시너지가 일어나 하루가 멀다하고 새로운 언어, 개념이 생성되고 있다.

하지만 그 아무리 새로운 언어로 구현한 소프트웨어라 하더라도, 결과적으로 프로그램의 실행 주체는 컴퓨터에게 있다. 우리가 아무리 새로운 언어니, 프레임워크니, 기술이니 지지고 볶고 하더라도 결국은 컴퓨터가 알아먹을 수 있어야 실행된다는 얘기다.

글로벌 시대답게 초등학생도 1개 이상의 외국어를 하는 마당에, 안타깝게도 우리 컴퓨터는 개발 이래로 초지일관 기계어만을 고집한다. 한글, 영어는 고사하고 우리가 개발할 때 사용하는 프로그래밍 언어라고 하는 대부분의 언어들. 심지어 C언어 보다도 저수준인 어셈블리어 조차 컴퓨터 입장에서는 외계어와 다를 바 없다.

우리가 일상생활에서 외국어를 접할 때, 번역기라는 걸 사용해서 한글로 번역하면 우리가 비교적 쉽게 이해할 수 있다. 그렇다면 이 프로그래밍 언어들을 컴퓨터가 이해할 수 있는 기계어로 번역해준다면, 컴퓨터는 우리가 짠 코드를 이해하고 코드를 실행시킬 수 있을 것이다. 이를 위해 모든 언어는 해당 언어를 기계어로 번역할 수 있는 도구를 사용하여 기계어로 번역한다. 이 번역기들은 방식에 따라 크게 두 가지로 구분할 수 있는데, 컴파일러인터프리터다.

Compiler(컴파일러) 🔗

컴파일러는 소스코드 전체를 기계어로 번역해주는 도구다. 기계어로 번역된 결과물이 생성되고, 프로그램 실행 시 번역한 결과물을 실행한다. 굳이 기계어가 아니더라도, 원래의 원시코드(소스코드) 전체를 목적코드(기계어 등)로 번역한다면 컴파일러라 할 수 있다. 핵심은 전체 원시코드를 다른 코드로 변환함에 있다. 컴파일러 아래와 같은 특징을 가지고 있다.

  1. 소스코드 전체 번역
    이러한 특징으로 별도의 컴파일 시간이 요구되며, 코드 한 글짜만 변경하더라도 재컴파일을 수행해야 한다. 코드의 규모가 클 수록 컴파일에 요구되는 시간 또한 늘어난다.

  2. 빠른 속도
    이미 컴파일을 수행하여 기계어로 번역했기 때문에, 프로그램 실행 시점엔 컴퓨터가 별다른 작업 없이 해당 프로그램을 이해할 수 있다. 즉, 실행 속도가 인터프리터에 비해 대체적으로 빠르다.

  3. 플랫폼 의존성
    컴파일러는 컴파일한 컴퓨터의 CPU, OS에 해당하는 기계어로 번역한다. 즉, CPU나 OS의 구조가 다른 컴퓨터에선 정상적인 동작을 보증할 수 없다. 이와 더불어, 특정 PC에 맞게 컴파일하려면 특정 PC의 CPU와 OS를 가진 컴퓨터가 필요하다.

  4. 강한 보안
    소스코드의 결과물이 기계어로 번역된 실행 파일이므로 보안이 상대적으로 우수하다. 단, 이는 어디까지나 상대적인 것으로, 실행 파일의 암호화나 소스코드의 난독화가 되어있지 않을 경우, 디컴파일, 해킹같은 분석기법을 통해 코드를 역설계할 수도 있다. 물론 이 자체로도 큰 분야이므로 많은 기술력을 요한다.

컴파일러를 차용하는 언어는 아래와 같다.

  • C계열 (C, C++, C#)
  • FORTRAN
  • Go
  • JAVA (기본적으론 컴파일러 방식)
  • Pascal
  • Rust
  • Visual Basic

대체적으로 초창기에 출시된, 역사가 깊은 언어가 대부분이다.

지금의 컴퓨터와 달리, 초창기 컴퓨터들은 사양이 그리 좋지 못 했다. VGA대란을 무시하고 보편적인 하이엔드급 컴퓨터 본체가 대략 200만원 선임을 감안할 때, 동일한 가격으로 90년대 컴퓨터는 CPU가 Intel Pentium 100, RAM은 8MB, HDD는 1GB였다. RAM의 경우 단위를 GB로 바꿔도 다소 부족함을 감안한다면 실로 엄청난 차이.

이러한 점으로 미루어보아 컴퓨터 자원을 낭비할 수 없었음이 당연할 것이다. 때문에 선처리 과정이 얼마나 걸리든 관계없이, 컴퓨터에서 가능한한 빠르고 가볍게 실행하는 것이 최우선 과제였을 것이다. 이러한 상황에서 초창기 언어들이 컴파일러를 차용한 것은 당연한 것이다.

Interpreter(인터프리터) 🔗

인터프리터는 실행 시 코드를 한 줄씩 읽어서 기계어로 번역하는 도구다. 한 줄씩 읽어서 실행하므로 별도의 결과물이 생성되지 않아 소스코드 자체가 실행 파일이 된다. 마찬가지로 굳이 기계어가 아니더라도 원래의 코드를 한 줄씩 읽어서 중간코드(기계어 등)으로 변환하여 실행한다면 인터프리터라 할 수 있다. 핵심은 원시코드를 한 줄씩 읽어서 변환함에 있다. 인터프리터는 아래와 같은 특징을 가지고 있다.

  1. 소스코드 한줄 씩 변경
    실행할 때마다 코드를 읽어서 번역하므로 컴파일이라는 작업 자체가 존재하지 않는다. 때문에 생산성이 매우 높다.

  2. 느린 속도
    컴파일 작업이 없는 대신, 프로그램 실행 시 코드 한 줄마다 작은 컴파일 작업이 이루어진다고 생각하면 된다. 때문에 컴파일러에 비해 상대적으로 실행 속도가 느리다.

  3. 플랫폼 독립성
    소스코드를 통해 프로그램을 실행하므로 컴퓨터의 CPU, OS의 영향을 받지 않는다. 해당 소스코드를 실행할 환경만 구축한다면, 어디서나 동일한 동작을 보증한다.

  4. 약한 보안
    소스코드 자체가 실행 파일이므로 코드가 유출되기 매우 쉽다. 중요한 동작이나 정보를 다룰 경우 난독화나 암호화를 반드시 해야한다. 이러한 보안작업은 오히려 프로그램의 실행 속도를 더욱 낮추기도 한다.(복호화 등의 작업 추가됨)

인터프리터를 차용하는 언어는 아래와 같다.

  • HTML
  • JavaScript
  • PHP
  • Python
  • Ruby

컴파일러와 달리 비교적 젊은 언어들이 차지하고 있다. 현대에 들어서면서 컴퓨터의 성능이 급격히 좋아짐에 따라 연산 속도도 증가했다. 이와 더불어 시간이 지나면서 인터프리터의 속도 이슈를 해결할 여러 기술들이 개발되기도 했다. 이와 같은 노력들이 인터프리터의 단점을 상쇄시켜줌에 따라 인터프리터의 장점인 높은 생산성이 부각됐다. 이러한 이유로 인터프리터의 언어는 비교적 최신 언어에 많이 적용되어있다.