컴파일러, 생각보다 어렵지 않을 수도 있어요
"컴파일러를 만들어보고 싶다"고 하면 대부분의 반응은 비슷해요. "그거 엄청 어렵지 않아?" 혹은 "드래곤 북 읽어야 하는 거 아니야?" 같은 반응이죠. 실제로 컴파일러 교과서의 대명사인 드래곤 북(Compilers: Principles, Techniques, and Tools)은 1000페이지가 넘는 방대한 분량이에요. 이걸 처음부터 끝까지 읽고 나서야 컴파일러를 만들 수 있다고 생각하면, 시작하기도 전에 지치겠죠.
그런데 prog21이라는 블로그에서 아주 파격적인 주장을 하고 있어요. 컴파일러를 만들고 싶으면 논문 딱 두 편만 읽으라는 거예요. 이 글은 2008년에 쓰인 건데, 시간이 지나도 여전히 유효한 조언이라서 지금까지도 꾸준히 회자되고 있어요.
그 두 편의 논문은 뭔가요?
첫 번째 논문은 Abdulaziz Ghuloum이 2006년에 쓴 "An Incremental Approach to Compiler Construction"이에요. 이 논문의 핵심 아이디어는 정말 단순해요. 컴파일러를 한 번에 완성하려고 하지 말고, 아주 작은 것부터 시작해서 점진적으로 기능을 추가하라는 거예요.
이게 뭐냐면, 보통 컴파일러를 만든다고 하면 렉서(코드를 토큰으로 쪼개는 단계), 파서(토큰을 구문 트리로 만드는 단계), 의미 분석, 최적화, 코드 생성 이런 걸 전부 설계하고 나서 구현에 들어가잖아요. 그런데 Ghuloum의 접근법은 달라요. 1단계에서는 정수 하나를 컴파일하는 컴파일러를 만들어요. 진짜 숫자 42를 넣으면 42를 출력하는 어셈블리 코드를 생성하는 거예요. 그 다음 단계에서 단항 연산(예: -42)을 추가하고, 그 다음에 이항 연산(예: 3 + 4)을 추가하고, 이런 식으로 한 번에 하나씩 기능을 쌓아가는 거죠.
이 방식의 장점은 매 단계마다 실제로 동작하는 컴파일러가 있다는 거예요. 아무리 작더라도 완전히 동작하는 프로그램이니까 성취감도 느낄 수 있고, 디버깅도 훨씬 쉬워요. 새로 추가한 기능에서만 버그를 찾으면 되니까요.
두 번째로 추천되는 자료는 파싱(구문 분석) 기법에 관한 것인데요, 전통적인 컴파일러 교과서에서 다루는 복잡한 파서 생성기(yacc, bison 같은 도구) 대신, 재귀 하강 파서(recursive descent parser)나 PEG(Parsing Expression Grammar) 같은 더 직관적인 방식을 쓰라는 거예요. 재귀 하강 파서는 말 그대로 문법 규칙 하나하나를 함수로 만드는 방식이라서, 코드를 읽으면 문법이 바로 보여요. 별도의 도구 없이 순수하게 코드만으로 파서를 구현할 수 있어서 이해하기도 훨씬 쉽고요.
왜 이 접근법이 지금도 유효한가
2008년 이후로 컴파일러 분야는 엄청나게 발전했어요. LLVM이라는 거대한 컴파일러 인프라 프로젝트가 사실상 업계 표준이 되었고, Rust의 컴파일러, Swift의 컴파일러 등 현대적인 언어들이 LLVM을 백엔드로 사용하고 있죠. 또 최근에는 Cranelift 같은 새로운 코드 생성 백엔드도 등장했어요.
그런데 흥미로운 건, 이런 거대한 프로젝트들도 결국 기본 원리는 같다는 거예요. 소스 코드를 읽어서 중간 표현(IR)으로 바꾸고, 그걸 최적화하고, 최종 기계어 코드를 생성하는 흐름은 동일하거든요. Ghuloum의 점진적 접근법으로 작은 컴파일러를 만들어보면, 이 전체 파이프라인을 직접 경험하게 되는 거예요.
비교해보면, 요즘 인기 있는 컴파일러 학습 자료로는 Crafting Interpreters(Robert Nystrom 저)가 있어요. 이 책도 비슷한 철학을 따르고 있는데, 처음부터 동작하는 인터프리터를 만들면서 점진적으로 기능을 추가하는 방식이에요. 온라인에서 무료로 읽을 수 있기도 하고요. 그리고 LLVM 튜토리얼도 "Kaleidoscope"라는 간단한 언어의 컴파일러를 단계별로 만들어보는 형식으로 구성되어 있어요. 결국 업계 전반에서 "작게 시작해서 키워나가자"는 접근법이 검증된 셈이죠.
한국 개발자에게 컴파일러 지식이 왜 필요할까
"나는 웹 개발자인데 컴파일러를 왜 알아야 해?"라고 생각할 수도 있어요. 그런데 실제로 컴파일러 지식이 도움되는 상황은 의외로 많아요.
DSL(Domain Specific Language, 특정 목적에 맞는 소규모 언어)을 만들어야 하는 경우가 대표적이에요. 설정 파일 파서, 쿼리 언어, 템플릿 엔진 같은 걸 만들 때 파싱 기법을 알면 훨씬 깔끔하게 구현할 수 있거든요. 또 TypeScript, Babel, ESLint 같은 도구들이 내부적으로 AST(Abstract Syntax Tree, 추상 구문 트리)를 다루는데, 이런 개념을 이해하면 빌드 도구나 린터 플러그인을 만들 때도 큰 도움이 돼요.
그리고 요즘 뜨거운 AI 분야에서도 컴파일러 기술이 쓰이고 있어요. 딥러닝 모델을 최적화하는 XLA, TVM 같은 ML 컴파일러가 있는데, 이 분야는 아직 인력이 부족해서 기회가 많아요.
실제로 시작해보고 싶다면, Ghuloum의 논문을 읽은 다음에 좋아하는 프로그래밍 언어로 정수 하나를 컴파일하는 것부터 시작해보세요. 정말 코드 몇십 줄이면 첫 번째 버전이 완성돼요. 그 작은 성공 경험이 다음 단계로 나아가는 원동력이 되거든요.
정리하자면
컴파일러는 두꺼운 교과서를 정복한 사람만 만들 수 있는 게 아니에요. 핵심 원리를 담은 논문 한두 편을 읽고, 아주 작은 것부터 직접 만들어보는 게 가장 효과적인 학습법이에요.
여러분은 컴파일러나 인터프리터를 직접 만들어본 경험이 있나요? 혹시 있다면, 어떤 접근법이 가장 도움이 됐는지 공유해주세요!
🔗 출처: Hacker News
"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"
실제 수강생 후기- 비전공자도 6개월이면 첫 수익
- 20년 경력 개발자 직강
- 자동화 프로그램 + 소스코드 제공