Language

컴파일러와 AST - 코드가 실행되는 과정

2025-06-29 21:29


컴파일러와 AST - 코드가 실행되는 과정

시작하기

우리가 작성한 코드는 컴퓨터에서 어떻게 실행하고 있을까?
개발자가 작성한 코드 한 줄이 어떤 과정을 거쳐서 컴퓨터가 읽고 실행할 수 있는지 컴파일러와 AST에 대해 자세히 알아보자.

컴파일러란?

AST에 대해 알아보기 전에 우선 컴파일러가 무엇인지 알아보자.
컴파일러란 일반적으로 한 언어를 다른 언어로 변환하는 역할을 한다.

개발자가 작성하는 Python, Java, C#, JavaScript 등과 같은 고급 언어는 사람이 이해하기 쉬운 언어이지만, 컴퓨터는 0과 1로 이루어진 기계어만 이해를 한다.
이때 고급언어를 저급언어(기계어)로 번역해주는 도구가 필요한데, 그것이 바로 컴파일러이다.

고급언어 → 컴파일러(번역) → 기계어

예를 들면, 한글을 파파고 번역기로 영어로 번역하는 것처럼, 파파고가 바로 컴파일러의 역할을 한다고 생각하면 된다.

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

그렇다면 컴파일러와 다른 번역기들은 어떤 차이점이 있을까? 간략하게 알아보자. 아래는 개념 이해에 도움이 되었던 유튜브 영상도 함께 소개한다.

인터프리터

컴파일러

하이브리드 방식 언어

컴파일러와 인터프리터가 어떤 녀석인지 개념적으로 큰 틀이 잡혔다면, 우리가 사용하는 개발 언어들은 어떻게 실행되고 있을까? 예를 들어 자바스크립트는 인터프리터와 컴파일어의 특징을 모두 가지고 있다. 초기에는 순수한 인터프리터 방식으로 동작했지만, 웹 규모가 점점 커짐에 따라 실행 속도가 빨라져야했다. 그래서 지금의 자바스크립트는 JIT(Just-In-Time) 컴파일러 방식을 사용하고 있다.

AST 정의

그렇다면 컴파일러가 이러한 번역과정을 어떻게 처리하고 있을까? 단순히 문자열인 코드를 곧바로 기계어로 바꾸는 건 쉽지 않다. 이때 중요한 역할을 하는 녀석이 바로 AST(Abstract Syntax Tree, 추상 구문 트리)이다.

AST란 프로그래밍 언어로 작성된 소스 코드를 컴퓨터가 이해하기 쉽도록 트리(Tree) 형태로 표현한 자료구조이다. 코드의 구조와 의미를 추상화 시켜서 계층적으로 보여준다.

AST가 있기 전에는 어떻게 처리했을까?

단순히 코드를 문자열 그대로 해석하거나, 파싱 과정에서 생성되는 파스 트리(Parse Tree)를 그대로 사용하는 경우가 많았다. 하지만 이 방법들은 코드의 의미를 파악하고 처리하는 데 있어서 비효율적이고 복잡하다는 단점이 있었다.

파스 트리(Parse Tree)와 AST의 차이점

AST와 파스 트리 모두 코드의 구조를 나타내지만 표현하는 방식에서 차이가 있다. a + b * c; 라는 코드를 예시로 살펴보자

파스 트리 (Concrete Syntax Tree)

문법 규칙을 모든 레벨에서 다 표현하는 특징이 있다. 코드의 모든 문법적인 요소를 그대로 다 담고있고, 심지어 불필요한 중간 노드나 괄호 ,연산자 우선순위와 관련된 세부적인 규칙까지 전부 포함하고 있다. 구조가 복잡해서 가독성이 낮다

expr
├── expr
│ └── id(a)
├── +
└── term
├── id(b)
└── *
└── id(c)

AST (Abstract Syntax Tree)

반면에 AST는 의미상 중요한 것만 추려내서 간결하게 표현한다. 코드의 논리적인 의미를 반영해서 핵심적인 구조만 나타낸다. 컴파일러 내부에서 주로 사용되고 구조가 단순해서 가독성이 훨씬 높다

     +
     / \
    a   *
       / \
      b   c

예시 코드

다음과 같은 코드가 있으면, 이 코드를 간단하게 표현한 AST 구조는 다음과 같다. let x = 5 + 3;

AST 구조

VariableDeclaration
├── kind: "let"
└── declarations:
    └── VariableDeclarator
        ├── id: Identifier("x")
        └── init:
            BinaryExpression
            ├── operator: "+"
            ├── left: Literal(5)
            └── right: Literal(3)

AST의 역할

1. 의미 분석 (Semantic Analysis)

2. 최적화 (Optimization)

3. 코드 생성 (Code Generation)

실제 사용 예시

AST 는 컴파일러 내부에서만 사용되지 않고 우리가 사용하는 개발 도구에서도 사용되고 있다.

Babel : 자바스크립트 트랜스파일링

Babel은 최신 버전 자바스크립트(ES6+) 코드를 구형 브라우저에서도 동작할 수 있도록 이전 자바스크립트 코드로 변환해주는 트랜스파일러이다

JSX → React 코드로의 변환 과정

JSX는 JavaScript의 확장 문법이지만 브라우저가 직접 이해하지 못하기 때문에 Babel이 AST를 활용해 변환한다.

const element = <h1>Hello</h1>;

이 JSX 코드는 실제 브라우저에서 실행되기 위해서 다음과 같이 자바스크립트 코드로 변환된다.

const element = React.createElement("h1", null, "Hello");

1. JSX 코드 → AST로 파싱 (Parsing) Babel은 먼저 입력된 JSX 코드를 읽어서 AST로 변환하고 이때 JSX 문법에 해당하는 JSXElement, JSXText 등의 노드가 생성된다.

{
  "type": "VariableDeclaration",
  "declarations": [
    {
      "type": "VariableDeclarator",
      "id": { "type": "Identifier", "name": "element" },
      "init": {
        "type": "JSXElement",
        "openingElement": {
          "type": "JSXOpeningElement",
          "name": { "type": "JSXIdentifier", "name": "h1" },
          "attributes": []
        },
        "children": [
          {
            "type": "JSXText",
            "value": "Hello"
          }
        ]
      }
    }
  ]
}

2. JSX 관련 노드를 CallExpression (React.createElement) 형태로 변환

Babel의 JSX 플러그인 (@babel/plugin-transform-react-jsx)이 이 AST를 순회하며 변환(Transform) 작업을 수행합니다. 이 플러그인은 JSXElement와 같은 JSX 관련 노드를 CallExpression 노드, 즉 React.createElement 함수 호출 형태로 변경한다.

{
  "type": "CallExpression",
  "callee": {
    "type": "MemberExpression",
    "object": { "type": "Identifier", "name": "React" },
    "property": { "type": "Identifier", "name": "createElement" }
  },
  "arguments": [
    { "type": "StringLiteral", "value": "h1" },
    { "type": "NullLiteral" },
    { "type": "StringLiteral", "value": "Hello" }
  ]
}

3. AST → 새 코드로 출력 (Code Generation)

수정된 AST를 바탕으로 코드 생성기(Code Generator)가 실제 브라우저가 이해할 수 있는 자바스크립트 코드로 생성해서 출력한다. Babel 뿐만 아니라 ESLint는 자바스크립트 코딩 규칙을 잘 지니는지, 실수한 코드가 없는지 검사하면서 AST를 사용하고, Prettier 포매터도 AST를 사용해서 코드를 재정렬을 시켜준다.

요약

Reference




 AST  추상구문트리  컴파일러  코드실행과정  프로그래밍언어처리