컴파일러란 무엇입니까?

집에서 컴퓨터로 작업하는 여성

작성자

Josh Schneider

Staff Writer

IBM Think

Ian Smalley

Staff Editor

IBM Think

컴파일러란 무엇인가요?

컴파일러는 한 프로그래밍 언어(소스 언어)의 코드를 다른 프로그래밍 언어(대상 언어)로 변환하는 컴퓨터 프로그램 유형입니다.

컴파일러는 프로그램 기능을 유지하면서 고급 소스 코드를 저급 대상 코드(예: 어셈블리 언어, 개체 코드 또는 기계어 코드)로 변환하는 데 사용됩니다.

현대적이고 실용적인 컴퓨터 프로그래밍의 핵심 도구인 컴파일러를 사용하면 프로그래머가 사람이 읽을 수 있는 고급 언어로 작업할 수 있도록 하며, 이어서 소스 코드를 실행 가능한 대상 코드로 변환합니다. 컴파일러는 또한 소프트웨어 개발자가 향상된 보안, 안정성 및 이식성을 갖춘 효율적인 실행 가능한 프로그램을 만들 수 있도록 합니다. 이것이 가능한 이유는 컴파일러가 오류를 식별하고 해결할 수 있도록 도움을 주어 이식 가능한 실행 가능 애플리케이션을 만들기 때문입니다. 

모든 컴파일러는 높은 수준의 코드를 하위 수준의 실행 코드로 변환하지만, 프로그래밍 언어와 애플리케이션에 따라 다양한 유형의 컴파일러가 사용됩니다. 예를 들어, 크로스 컴파일러는 실행 중인 것과 다른 유형의 CPU 또는 운영 체제에 대한 코드를 생성하는 데 사용됩니다.

이상적인 컴파일러를 사용할 수 없거나 아직 빌드되지 않은 경우 특정 프로그래밍 언어를 컴파일하는 데 더 최적화된 보다 영구적인 컴파일러를 컴파일하기 위해 임시 부트스트랩 컴파일러가 사용됩니다.

기타 관련 소프트웨어의 간단한 목록은 다음과 같습니다.

  • 디컴파일러는 리버스 컴파일러처럼 작동하며 저급 코드를 고급 언어로 변환합니다.
  • 소스 간 컴파일러(또는 트랜스파일러)는 고급 코드를 다른 고급 언어로 변환합니다.
  • 언어 재작성기는 언어를 변경하지 않고 형식 코드 표현식을 다른 형식으로 변환합니다.
  • 컴파일러-컴파일러는 재사용 가능한 일반 컴파일러, 또는 프로젝트별 목적에 맞게 통합할 수 있는 컴파일러 구성 요소를 만드는 데 사용됩니다.  

전문가의 인사이트를 바탕으로 한 최신 기술 뉴스

Think 뉴스레터를 통해 AI, 자동화, 데이터 등 가장 중요하고 흥미로운 업계 동향에 대한 최신 소식을 받아보세요. IBM 개인정보 보호정책을 참조하세요.

감사합니다! 구독이 완료되었습니다.

구독한 뉴스레터는 영어로 제공됩니다. 모든 뉴스레터에는 구독 취소 링크가 있습니다. 여기에서 구독을 관리하거나 취소할 수 있습니다. 자세한 정보는 IBM 개인정보 보호정책을 참조하세요.

컴파일러 작동 방식

실제로 컴파일러를 사용하는 것은 Linux (또는 동급) 시스템의 명령줄에 명령을 입력하고 컴파일러 실행 파일과 컴파일할 소스 파일을 지정하는 것만큼 간단할 수 있습니다. 이 명령은 시스템에 소스 코드를 처리하도록 지시하여, 대상 기계어로 컴파일하고 실행 프로그램을 생성하는 데 필요한 개체 파일을 생성합니다. 

C 코드를 C 프로그램으로 컴파일하는 데 일반적으로 사용되는 강력한 C 컴파일러 컬렉션인 GNU 컴파일러 컬렉션(GCC) 또는 대체 Clang과 같은 오픈 소스 컴파일러는 GitHub와 같은 리포지토리에서 사용할 수 있습니다. 다른 컴파일러는 다양한 공급 업체를 통해 자유롭게 설치하거나 구매할 수 있습니다. 또한 텍스트 편집기, API 문서 및 디버깅 도구 등 소프트웨어 개발에 필요한 다양한 유틸리티를 묶어서 제공하며 널리 사용되는 통합 개발 환경(IDE)에도 구축할 수 있습니다.     

사용하는 특정 컴파일러에 관계없이 코드를 컴파일하는 과정에는 다양한 수준의 분석, 최적화 및 궁극적으로 코드 생성을 통해 소스 코드를 전달하는 과정이 포함됩니다. 소스 코드는 여러 분석 계층을 순차적으로 통과하며 프로세스의 각 단계를 통해 평가됩니다.

컴파일러가 원본 소스 코드에 문제가 있음을 인식하면 오류 메시지를 반환하여 개발자에게 나머지 코드 컴파일을 진행하기 전에 식별된 오류를 해결하라는 메시지를 표시할 수 있습니다. 일반적으로 컴파일러는 다음 단계를 진행합니다.

  1. 어휘 분석: 컴파일의 첫 번째 단계에서는 문자를 알려진 키워드, 식별자, 연산자와 같은 의미 있는 언어 단위로 변환하는 프로그램인 컴파일러의 렉서(lexer)를 통해 소스 코드를 전달합니다. 이러한 단위를 총칭하여 토큰이라고 합니다. 이 단계에서는 기본적으로 소스 코드의 의미 있고 중요한 요소를 컴파일러가 작업할 수 있는 토큰으로 변환함으로써 다음 단계를 위한 소스 코드를 준비합니다. 
  2. 구문 분석: 컴파일 과정의 두 번째 단계는 렉서(lexer)에서 컴파일러의 파서(parser)로 토큰을 보내는 것입니다. 파서는 코드에 구문 오류가 있는지 확인하고 소스 코드가 소스 언어의 규칙을 제대로 따르는지 확인하는 프로그램입니다. 구문 분석기가 구문 분석 중에 오류를 감지하지 못하면 추상 구문 트리(AST)라고 하는 전체 코드 구조의 추상 표현을 생성합니다.
  3. 의미 분석: 컴파일러는 코드 구문을 확인한 후 구문 분석된 코드에 대한 의미 분석을 수행하여 소스 코드의 의도된 기능을 추론합니다. 이 단계에서 컴파일러는 선언되지 않은 변수 또는 잘못된 연산자 사용과 같은 논리적 오류에 대한 검사를 수행합니다.
  4. 최적화: 작동하는 코드를 생성하는 데 반드시 필요한 것은 아니지만, 최적화는 컴파일된 코드의 성능을 개선하기 위해 많은 컴파일러에서 공통적으로 사용하는 선택적 단계입니다. 최적화를 통해 불필요한 코드를 식별하고 제거하여 더 빠르고 효율적이며 안정적인 프로그램을 만들 수 있을 뿐만 아니라 최종 디버깅 프로세스도 단축할 수 있습니다. 
  5. 코드 생성: 프로세스의 마지막 단계에서 컴파일러는 AST를 기계가 읽을 수 있는 코드로 변환합니다. 코드 생성의 최종 아웃풋은 바이너리 코드로 변환되어 컴퓨터 시스템에서 실행할 수 있는 어셈블리 언어 코드입니다. 
AI 아카데미

하이브리드 클라우드로 AI 지원 실현하기

IBM 사고 리더들이 이끄는 이 커리큘럼은 비즈니스 리더들에게 성장을 촉진하는 AI 투자의 우선순위를 정하는 데 필요한 지식을 제공합니다.

3단계 컴파일러 구조

일부 컴파일러는 위의 구조를 엄격하게 준수하지 않을 수 있습니다. 그러나 일부 컴파일러에는 더 많거나 적은 단계가 포함될 수 있지만 컴파일의 모든 단계는 프론트엔드, 미들엔드, 백엔드의 세 단계 중 하나에 귀속될 수 있습니다.

이 3단계 구조를 통해 컴파일러는 모듈식 접근 방식을 취할 수 있습니다. 이를 통해 다양한 언어에 대한 여러 프론트엔드와 다양한 CPU에 대한 백엔드를 결합할 수 있으면서, 다양한 관련 미들엔드의 최적화 기능을 공유할 수 있습니다.

컴파일러의 세 단계에는 다음과 같은 분포가 수반됩니다.

  1. 프론트엔드: 컴파일러의 프런트엔드에는 어휘 분석, 구문 분석 및 의미 분석 측면이 포함됩니다. 이 단계에서는 소스 언어의 규칙에 따라 구문과 의미를 검증하고 소스 코드의 오류를 식별하여 정확히 찾아낼 수 있습니다. 오류가 발견되지 않는다고 가정하면 컴파일러의 프론트엔드에서는 소스 코드를 중간 표현(IR, 소스 코드의 임시 하위 수준 변환)으로 변환하여 미들엔드에 전달합니다. 
  2. 미들엔드: 컴파일러의 미들엔드 단계는 전체 컴파일 프로세스에서 타깃으로 삼는 CPU 아키텍처와 무관하게 IR에서 다양한 코드 최적화를 수행합니다. 대상 기계어 코드와 독립적으로 소스 코드에 대한 최적화를 구현함으로써 컴파일러는 여러 버전에서 코드 성능을 향상시킬 수 있는 일반화된 최적화를 적용할 수 있습니다. 이러한 개선은 지원되는 특정 언어 또는 하드웨어 아키텍처에 관계없이 수행할 수 있습니다. 
  3. 백엔드: 백엔드 단계는 미들엔드 단계의 아웃풋을 사용하며, CPU별 최적화 및 변환 작업을 수행할 수도 있습니다 컴파일 프로세스의 이 마지막 단계에서 컴파일러는 레지스터 할당과 명령 스케줄링을 포함한 대상 종속 어셈블리 코드를 아웃풋합니다. 백엔드 단계에서는 일반적으로 대상 운영 체제와 하드웨어에 특화된 머신 코드를 생성합니다. 

컴파일러 사용의 이점

컴파일러가 실행 가능한 코드를 생성하는 데 명시적으로 필요한 것은 아니지만 코딩 언어와 기계 환경의 다양성과 복잡성으로 인해 컴파일러는 실행 가능한 소프트웨어를 만드는 데 실질적으로 필요합니다. 다음은 소프트웨어 컴파일러를 사용할 때 얻을 수 있는 네 가지 주요 이점입니다.

고급 언어 코딩 촉진

고급 프로그래밍 언어는 음성 언어에 더 가까운 구문과 키워드를 사용하므로 개발자가 훨씬 쉽게 사용할 수 있습니다. 컴파일러는 사람이 읽을 수 있는 이 코드를 최적화된 소프트웨어 애플리케이션을 실행하는 데 필요한 더욱 복잡한 머신 코드로 변환합니다.

고급 언어의 몇 가지 예는 다음과 같습니다.

  • Python(웹 개발, 데이터 과학 등에 사용됨)
  • Java™(Android 개발, 엔터프라이즈 애플리케이션 등에 사용됨)
  • C++(게임 개발, 운영 체제 등에 사용됨)
  • JavaScript(동적 및 대화형 웹 개발에 사용)
  • PHP(웹 개발의 서버 측 스크립팅에 사용)
  • C#(Windows 애플리케이션, Unity 엔진 게임 개발에 사용)
반복 감소

컴파일러는 고수준 코드를 실행 가능한 머신 코드로 변환하여 효율성을 개선합니다. 컴파일러의 아웃풋은 .exe 파일 확장자로 저장되며, 이 파일 확장자는 컴퓨터에서 직접 실행됩니다. 컴파일러 덕분에 실행 가능한 프로그램 작성은 한 번만 수행하면 되는 작업이 되었습니다.

컴파일이 완료되면 필요한 횟수만큼 컴파일된 코드를 실행할 수 있습니다. 이 프로세스 덕분에 특정 애플리케이션 또는 애플리케이션의 일부를 런타임 소프트웨어 작업과 분리하여 실행할 수 있어, 프로그램을 전반적으로 더 빠르고 효율적으로 실행할 수 있습니다

이식성 향상

모든 시스템에서 모든 유형의 프로그래밍 코드를 실행할 수 있는 것은 아닙니다. 컴파일러는 개발자가 선호하는 코드 유형을 시스템이 작동하는 데 필요한 코드 유형으로 변환하는 데 사용됩니다. 이러한 방식으로 컴파일러는 소프트웨어를 다양한 운영 체제 및 하드웨어 아키텍처에서 쉽게 저장, 전송 및 실행할 수 있는 다양한 호환 언어로 변환하여 프로그램 이식성을 향상시킵니다.

전반적인 최적화 촉진

컴파일 프로세스 중에 컴파일러를 사용하여 소프트웨어 오류와 결함을 식별하고 해결하여 보다 안정적이고 더 최적화된 프로그램을 만들 수 있습니다. 컴파일러는 또한 버퍼 오버플로와 같은 메모리 관련 오류를 방지하여 소프트웨어 보안을 개선하고 잠재적인 메모리 문제가 감지되면 경고를 생성할 수 있습니다. 

컴파일러와 인터프리터 비교

컴파일러는 소스 코드를 실행 가능한 머신 코드로 변환하는 데 사용되는 반면, 인터프리터는 또 다른 유형의 프로그램으로 유사한 기능을 제공하지만, 다른 메커니즘을 통해 제공됩니다.

인터프리터는 소스 코드를 변환하는 대신 소스 코드를 직접 실행하거나 소스 코드의 플랫폼 독립 저급 표현인 바이트코드라는 중간 코드를 사용합니다. 바이트코드는 컴퓨터 하드웨어에서 직접 실행하지 않고 가상 머신(VM)에서 실행하도록 설계된, 사람이 읽을 수 있는 소스 코드와 머신 코드 사이의 중개자 역할을 합니다. 

이론적으로 모든 프로그래밍 언어는 컴파일러나 인터프리터로 실행할 수 있습니다. 그러나 개별 프로그래밍 언어는 컴파일이나 해석에 더 적합한 경향이 있습니다.

실제로 컴파일러 언어와 인터프리터 언어의 구분은 컴파일러와 인터프리터 자체의 구분과 마찬가지로 두 유형의 프로그램의 기능이 겹칠 수 있어 때때로 모호할 수 있습니다. 일부 언어는 더 일반적으로 컴파일되고 일부는 더 일반적으로 해석되지만, 일반적으로 해석되는 언어에 대해 컴파일러를 작성할 수 있으며 그 반대의 경우도 마찬가지입니다.

고급 언어는 일반적으로 컴파일 또는 해석과 같은 변환 유형을 염두에 두고 생성되지만 이는 엄격한 제한이라기보다는 제안에 가깝습니다. 예를 들어, BASIC은 종종 해석 언어로, C는 컴파일 된 언어로 칭해지지만, C 인터프리터가 있는 것처럼 BASIC용 컴파일러도 있습니다. 

인터프리터와 컴파일러의 주요 차이점은 타이밍과 최적화에 있습니다. 두 유형의 프로그램 모두 소스 코드를 먼저 동작 가능한 대상 코드로 변환한 후, 이를 최적화하려고 합니다.

운영 환경에 따라 컴파일되거나 해석된 코드는 하드웨어 능력, 메모리 및 스토리지 용량을 고려하여 효율적으로 실행하는 데 더 적합할 수 있습니다. 특정 프로그램, 애플리케이션 및 하드웨어의 제약 조건에 따라 컴파일, 해석 또는 이 둘의 조합이 최상의 결과를 얻을 수 있습니다. 

따라서 인터프리테이션이 컴파일을 완전히 대체할 수는 없지만, 점진적인 변환 프로세스를 통해 컴파일 작업을 백그라운드로 옮길 수 있습니다. 컴파일러는 실행 가능한 파일을 생성하기 전에 소스 코드를 완전히 대상 코드로 변환하는 사전(AOT) 변환 전략을 사용합니다.

인터프리터는 애플리케이션이 필요로 하는 코드를 직접 실행하거나 바이트코드를 매개체로 사용하여 가상 머신 실행 가능 소스 코드를 아웃풋합니다. 이러한 방식으로 인터프리터는 속도 향상이나 유연성과 같은 이점을 제공할 수 있지만, 어느 시점에서는 실행 스택의 마지막에는 직접 실행되는 머신 명령어 집합을 제공해야 합니다.

경량 효율성이 우선시되는 경우에는 JIT(Just-In-Time) 변환을 수행할 수 있는 기능 때문에 컴파일러보다 특수 인터프리터가 선호될 수 있습니다. JIT는 소스 코드 조각을 대상 코드로 컴파일하고 즉시 실행되도록 메모리 버퍼로 다시 컴파일하는 전략입니다. JIT 해석은 온디맨드 방식으로 코드를 컴파일하며, 기존 컴파일러의 일회성 컴파일 효율성과 코드를 반복적으로 실행할 수 있는 유연성(종종 표준 바이트코드 인터프리터보다 빠름)을 결합합니다.

그러나 상황에 따라 달라지는 바이트 코드 해석과 함께 JIT 컴파일에 대한 최신 추세가 증가함에 따라 많은 컴파일러가 컴파일 및 해석 기능을 모두 제공하도록 설계되고 있습니다. 이러한 중복으로 인해 이 두 카테고리 간의 경계가 더욱 흐려집니다. 

관련 솔루션
IBM Cloud Infrastructure Center 

IBM Cloud Infrastructure Center는 IBM zSystems 및 IBM LinuxONE에서 프라이빗 클라우드의 인프라를 관리하기 위한 OpenStack 호환 소프트웨어 플랫폼입니다.

IBM Cloud Infrastructure Center 살펴보기
IT 인프라 솔루션

엔터프라이즈 하이브리드 클라우드 및 AI 전략을 위해 설계된 서버, 스토리지 및 소프트웨어를 살펴보세요.

토목 인프라 솔루션 살펴보기
클라우드 인프라 솔루션

비즈니스 요구에 적합한 클라우드 인프라 솔루션을 찾고 필요에 따라 리소스를 확장하세요.

클라우드 솔루션
다음 단계 안내

IBM의 하이브리드 클라우드 및 AI 지원 솔루션으로 기업 인프라에 혁신을 일으키세요. 비즈니스를 보호, 확장 및 현대화하도록 설계된 서버, 스토리지 및 소프트웨어를 살펴보거나 전문가 인사이트에 액세스하여 생성형 AI 전략을 강화하세요.

토목 인프라 솔루션 살펴보기 eBook 다운로드