
'컴파일러를 만들어본다'는 건 많은 개발자들의 버킷리스트 중 하나예요. 요즘 새로 등장한 시스템 언어 Zig로 C 컴파일러를 직접 만드는 시리즈가 공개됐는데요, 읽어보니 꽤 흥미로워서 오늘 같이 뜯어볼게요. Zig를 써본 적 없는 분들도 이 글 하나로 감을 잡을 수 있게 풀어드릴게요.
왜 하필 Zig로 C 컴파일러일까요
일단 C 컴파일러를 구현하는 건 컴파일러 공학의 고전 주제예요. Nora Sandler의 Writing a C Compiler라는 책이 이 분야의 표준 교재 중 하나고, 많은 사람들이 이 책을 따라가며 OCaml이나 Rust로 구현해보곤 하죠. 근데 이번 블로그 시리즈의 저자는 이걸 Zig로 구현하기로 했어요. 이유가 재밌어요.
첫째, Zig 자체가 시스템 프로그래밍 언어로 설계됐기 때문에 컴파일러처럼 메모리와 성능에 민감한 소프트웨어를 만들 때 딱 맞아요. 둘째, Zig는 comptime이라는 강력한 컴파일 타임 메타프로그래밍 기능을 제공하는데, 파서나 코드 생성기를 만들 때 이게 엄청 유용해요. 셋째, Zig 자체가 LLVM과 긴밀히 연동되고, 사실상 C/C++ 컴파일러를 내장하고 있어서 '어떻게 네이티브 바이너리를 뽑는가'를 배우기에 좋은 생태계거든요.
Zig가 어떤 언어냐면요
Zig(지그)는 Andrew Kelley가 만든 C의 현대적 대체제를 목표로 하는 언어예요. Rust와 자주 비교되는데, 철학이 꽤 달라요. Rust는 '컴파일러가 메모리 안전을 증명하게 만들자'라는 방향이라면, Zig는 'C처럼 단순하게 유지하되 불편한 부분들을 깎아내자'에 가까워요.
구체적으로는 이런 특징들이 있어요. null 대신 옵셔널 타입(?T)을 써요. 예외 대신 에러 유니언(!T)을 써서 함수가 실패할 수 있다는 걸 타입으로 표현해요. 매크로 대신 comptime 키워드로 컴파일 타임에 코드를 실행해 타입이나 상수를 만들어내요. 그리고 명시적 메모리 할당자(allocator)를 함수 인자로 주고받는 패턴이 일반적이에요. 이 덕분에 라이브러리가 어디서 얼마나 메모리를 쓰는지 호출자가 완벽히 통제할 수 있거든요. 아레나 할당자 하나 넘겨주고 끝나면 한 번에 해제하는 식이에요.
블로그의 핵심 흐름
1편은 어휘 분석(lexing)과 파서 스캐폴딩을 Zig로 만들어보는 과정이에요. C 소스 코드를 받아서 토큰으로 쪼개고, 이걸 AST(추상 구문 트리)로 만드는 기본기가 담겨 있어요. 저자는 여기서 Zig의 std.ArrayList, 할당자 패턴, 태그드 유니온(tagged union)을 써서 토큰과 AST 노드를 표현하는데, 이게 C로 같은 걸 짤 때보다 훨씬 깔끔해요.
특히 인상적인 건 에러 처리예요. 파서에서 예상 못한 토큰을 만났을 때, Rust라면 Result<_, ParseError>를 리턴하고, C라면 errno나 out 파라미터를 쓰겠죠. Zig는 !Expr처럼 에러 유니언을 리턴하고, 호출하는 쪽에서 try 키워드로 자연스럽게 전파해요. 문법이 예외만큼 간결한데 런타임 비용은 C 수준으로 낮아요.
업계 흐름에서의 위치
요즘 시스템 언어 판이 재미있어요. Rust가 리눅스 커널, 안드로이드, Windows까지 파고들면서 주류가 됐고, Zig는 Bun(JS 런타임), TigerBeetle(금융용 DB), Ghostty(터미널) 같은 인상적인 프로젝트들을 통해 세를 넓히고 있어요. 또 Mojo(AI용), Carbon(구글의 C++ 후속 실험) 같은 후보들도 등장했고요.
이런 흐름에서 'C 컴파일러 직접 짜보기'는 교육적 가치가 커요. 왜냐면 여러분이 앞으로 어떤 언어를 쓰든, 그 언어의 컴파일러가 내부에서 뭘 하는지 이해하면 성능 이슈, ABI 문제, 크로스 컴파일 설정 같은 주제가 완전히 다르게 보이거든요.
한국 개발자에게 주는 시사점
당장 실무에 Zig를 도입하기는 쉽지 않을 거예요. 생태계가 아직 1.0도 안 됐고, 국내 채용 수요도 거의 없어요. 하지만 사이드 프로젝트나 학습용으로 시도해볼 가치는 충분해요. 특히 성능 크리티컬한 라이브러리(이미지 처리, 오디오 디코더, 바이너리 파서 등)를 짤 때 Zig는 C보다 훨씬 안전하고, Rust보다 러닝커브가 완만해요.
그리고 컴파일러 공부는 절대 헛되지 않아요. 백엔드 개발자든 프런트엔드 개발자든, TypeScript 타입 시스템이나 Babel 같은 트랜스파일러, 심지어 React Compiler까지 결국 다 '소스 코드를 AST로 바꾸고 변환해서 다시 코드로 뽑는 일'이거든요.
마무리
한 줄 요약: Zig로 C 컴파일러를 짜는 건 두 마리 토끼를 잡는 학습 프로젝트예요 - 컴파일러의 내부 구조와 현대 시스템 언어의 설계 철학을 동시에 익힐 수 있거든요. Rust를 먼저 배우시던 분들이라면, Zig가 어떤 결을 제안하는지 보는 것만으로도 좋은 경험이 될 거예요. 여러분은 컴파일러/인터프리터를 직접 만들어본 적 있나요? 어떤 언어로 도전해보고 싶으세요?
🔗 출처: Hacker News
"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"
실제 수강생 후기- 비전공자도 6개월이면 첫 수익
- 20년 경력 개발자 직강
- 자동화 프로그램 + 소스코드 제공