💡 이 글은 2024-03-02를 기준으로 작성되었으며, 사내 스터디로 진행했던 ‘컴파일러 만들기’ 북 스터디 회고를 옮긴 글입니다
1. 교재
-
컴파일러 만들기 - 컴퓨터 프로그램의 구조와 원리 (유종원)
2. 배운 점
-
컴파일러는 1) 어휘 분석(tokenize) 2) 구문 분석(parse) 3) 인터프리트 or 코드 생성 과정을 거쳐 최종 산출물을 만들고 가상머신이나 OS 등의 실행 환경에서 정의된 내용들에 따라 동작하게 된다.
-
- 문자열을 분석하여 토큰화 하고
-
- 토큰으로부터 문법에 따라 문법 트리로 만들고
-
- 문법 트리를 기반으로 코드를 직접 실행하거나 실행 가능한 플랫폼 별 목적 코드로 변환
-
3. 좋았던 점
-
미적분을 처음 배울 때와 비슷한 기분이었던 것 같습니다. 무한과 미분과 적분이라는 개념을 알게 되었을 때 어떤 대상을 바라보는 시각의 축이 하나 더 생겼다고 느꼈는데요. 컴파일러에 대해 알아보면서도 컴퓨터에 대해 조금 더 저수준의 세계에서 일어나는 일을 상상할 수 있는 도구를 얻은게 아닌가 생각을 해보았습니다.
-
프로그래밍에서 컴파일러는 수학에서의 미적분처럼 여러 활용들의 근간이 되는 지식이었고, 이러한 컴파일러를 이루는 여러 단계들에 대해 살펴보며 우리가 일상적으로 사용 중인 기능들(ex. ESM, Bundler, 브라우저에서 Render Tree 파싱, tsc, ESLint, V8 Engine, …)에서 일부 / 전체 / 복합적으로 사용하고 있었다는 점을 알 수 있었습니다. 개인적으로 프론트엔드 개발자는 자칫 단순히 UI만 그리는 존재로 남기 쉽다고 생각하는데, 보다 엔지니어적인 역량을 쌓기 위해 꼭 필요한 과정이 아니었나 생각합니다.
-
특히 최근 프론트엔드 툴링 생태계는 런타임보다는 좀 더 직접적으로 빌드 타임에 컴파일러의 힘을 많이 빌리는 케이스가 늘어나고 있습니다. 대표적인 예시로 스타일드 컴포넌트 같은 css-in-js 방식(런타임 js → css 생성)에서 빌드 타임을 활용하는 (near) zero runtime 방식에 대한 선호, tailwind css에서 제공하는 JIT 방식 컴파일러, Vue나 Svelte, Angular 등에서 빌드 타임에 자체 컴파일러를 사용하여 성능적 이점을 얻던 것 처럼 React도 올해 하반기 쯤 자체 컴파일러(React Compiler - auto memoizing) 도입을 앞두고 있습니다. 아예 react-dom 패키지를 최적화 한 Million.js, Million Lint 같은 것도… 이런 것들이 어떤 원리로, 어떤 일들을 해주는지 미리 지도를 그려볼 수 있어서 좋았습니다.
-
워낙 CS 쪽 지식이 부족하다보니 혼자 컴파일러를 알아볼만한 근육이 없는 상황이었는데 여러 PT 쌤들 덕분에 얼렁뚱땅 한바퀴 돌 수 있어서 좋았습니다. 각 파트 별로 한번 설명을 듣고 그 다음 주에 구현을 하니 시행착오를 줄일 수 있어 좋았습니다.
-
간접적이지만 타이밍 좋게 업무에 도움을 받을 수 있었습니다. (A AND B) OR NOT C 같은 문자열을 다뤄서 뭔가를 만들어내야 했는데, 평소 같았다면 단순히 각 공백을 split 하거나 정규표현식을 사용해서 자르는 등의 접근을 했을 것도 같은데요. 컴파일러에 관심을 두고 있었던 덕분에 문자열을 파싱하고 AST로 변환해서 활용할 수 있겠다는 쪽으로 접근할 수 있었습니다. 구현은 좀 애도 먹고 어설프지만 결국 트리 내 특정 노드에 대한 치환이나 문법에 따른 문자열 하이라이팅 등의 기능이 들어가게 되어 결과적으로 올바른 선택이었다는 생각이 들었습니다.
-
그리고 이번 스터디에 가장 많은 도움을 주신 OpenAI에 감사의 인사를 전합니다 ^^ 언젠가 vite-zustand-selector-plugin으로 찾아뵙겠습니다 ^^
4. 아쉬운 점
-
0 → 1이 되었다는 점은 좋았으나, 교재가 좀 더 친절했으면 좋았겠다 하는 아쉬움은 있습니다. 물론 두꺼운 책을 골랐으면 끝을 못봤을 수도 있고, 주제가 주제다보니 서술이 어려울까봐 겁을 냈던 부분도 있었던거 같고요. 이 다음은 각자의 몫으로 남겨둬야 할거 같네요 ㅎㅎ 책은 역시 두꺼운 책이 친절하다는 진리를 다시 한번 곱씹어봅니다.
-
예제 코드의 코드 퀄리티가… 많이 아쉬웠습니다 ㅠ 구현이라도 깔끔했으면 좀 더 쉽게 이해했을거 같기도 해요. 물론 컴파일러는 성능 효율이 장땡이다! 라고 한다면 납득은 가지만서도 학습만 놓고 본다면 그건 또 다른 결의 이야기로 다룰 수 있었을거 같아요.
-
새로운 개념을 익힐 때는 헤멜 수 있는 영역을 최대한 좁히는게 좋다고 생각하는데요. C++에 익숙하지 않으신 분들은 컴파일러 개념 이해 + C++ 이해 이중고로 힘드셨을거 같아요. 저는 그래서 익숙한 타입스크립트를 사용했지만 어쨌든 C++ → TS 과정에서 버벅이는 시간이 적잖았네요.
-
이후의 과정들을 미리 알았다면 차근차근 유닛 테스트를 작성하며 진행을 했을 거 같습니다. 멀리까지 진도를 갔는데 앞에서 누락된 구현으로 인해 까마득하게 디버깅 시간을 부어야 했던 적이 더러 있었습니다…