마크다운 파서 만들기 (1) - 합리화와 사전조사

지난 글에 마크다운 문서로부터 Tufte CSS를 적용한 HTML 문서를 만들어내면 좋겠다고 썼다. 일일이 HTML 마크업을 꾸며 웹 문서를 만드는 일은, 아무리 훌륭한 에디터가 있다 해도 번거로운 일이기 때문이다.

그런데, 마크다운 표준 문법에는 Tufte CSS에서 쓰는 각주 표현이 없어서, 해당 기능을 덧붙여야 할 것 같다. 이미 세상에 좋은 마크다운 파서는 널려 있으므로, 그중 기능을 덧붙이기 쉬운 파서를 찾아서 손보면 될 것 같다. 아니면, 애써 파서까지 건드리지 않고도, Pandoc 같은 도구를 잘 써서 결과를 뽑을 수도 있을 것 같다.

한편, 어떤 문제를 해결할 때 맨바닥부터 만들어 쓰는 방법도 재미있고 유익한 때도 있다. 물론 이미 있는 바퀴를 재개발한다고 지적을 받기도 하고, 새로 만들어 봤자 이미 공개된 훌륭한 제품의 품질을 따라가기 어렵다는 면에서 삽질로 치부되기 쉽다. 그러나, 배우는 사람 입장에서는 가끔 흥미가 있는 주제를 잡아 직접 만들어 보는 것도 좋은 경험이 될 수 있다. 드는 시간과 노력의 관점에서 보면 비효율적이고, 결국 삽질 끝에 쓸모없는 걸 만들게 되기도 하지만 배우는 게 원래 그런 거지 뭐.

그리고 사실 회사 다닐 때와 가장 큰 차이점 중 하나는, 이제 더는 무언가를 할 때 나 자신을 포함한 누군가를 설득할 필요가 없다는 점이다. 원래 사람 심리가 그런 것인지, 아니면 오랜 사회생활로 물든 건지 모르겠지만, 반드시 무언가 합리적인 이유를 근거 삼아 일을 시작해야 한다는 강박감이 있는 것 같은데, 개인 프로젝트에는 그럴 필요가 없다. 그저 재밌을 것 같으면 하면 된다. 흥미가 가면 행동도 간다. 그렇다고 너무 다 바닥부터 만들려고 해도 문제이고, 너무 가져다가 쓰려고만 하는 접근도 옳지 않을 터. 각자 때때로 원하는 비율로 조절해서 작업하면 된다. 그러다 보면 뭐라도 배우는 거고.

암튼, 아직 그 강박을 벗어나지 못한채 이런 장황한 합리화를 거쳐, 손수 마크다운 파서를 만들어 보겠다는 마음먹었다. 고고씽.

마크다운 파서를 직접 만들어서 Tufte CSS를 적용한 HTML 문서를 마구 찍어내 보자.

파서 생성기를 배운 시절

파서 생성기(parser generator), 참 오랜만에 듣는 용어다. 학교 다닐 때, lex나 yacc 같은 스캐너(scanner)와 파서 생성기를 어쩔 수 없이 썼지만, 잘 알고 쓰는 건 아니고, 과제 하느라 아주 기본적인 사용법을 간신히 익히는 수준이었다.

컴퓨터 공학을 전공하지 않은 동료 개발자 중에 비전공자임에 열등감을 토로하는 분들이 가끔 있었는데, 사실 그런 열등감은 누구에게나 이따금 드러나는 수준이 아닌가 생각한다. 오히려 나 같은 전공자는, 본인이 비싼 등록금 내며 무려 4년이나 배웠고 분명 그 내용을 배우며 밤새워 과제를 하고 시험을 치렀다는 사실은 기억하지만, 정작 그 내용 자체는 이제 잘 모른다는 점에 콤플렉스가 있다. 어차피 지금 모르는데, 전공한 것과 아닌 것의 차이는 무엇인가?

어느 쪽이 더 열등한 건지는 모르겠지만, 아마도 열등감을 느끼는 사람이 열등한 거지, 전공했고 안 했고는 크게 중요한 기준점이 아닌 것 같다. 그냥 그럴 시간에 모르는 거 더 공부하면 되는 거다. 비전공자라고 주눅 들지 말자. 뭐 석박사도 아니고 고작 학사 전공한 것 가지고 으스대는 사람도 없을 텐데 왜 스스로 그러는지 모르겠다. 뭐, 이렇게 얘기하는 나도 전공 석박사 타이틀 있는 사람들에게 괜한 열등감이 스멀스멀 올라올 때도 있음을 고백한다. 그러니 이건 ‘있는 자의 어설픈 조언’이 아니라 ‘동병상련을 바탕으로 한 제안’이다, 우리 그러지 말자. 석박사는 석박사 나름 대로, 연구실에서 교수님 수발드는 동안 남들은 사회생활하면서 조금씩이나마 돈을 벌어 놓았다는 점을 부러워할지도 모른다. 그들은 그들대로 이제부터 돈 벌면 되고, 나는 나대로 이제부터라도 필요한 공부를 하면 되는 거다.

인스타파서: 클로저용 파서 생성기

원래 주제로 돌아오자. 이 글의 출발점인 인스타파서(instaparser)는 클로저에서 쓸 수 있는 라이브러리로, CFG(Context-Free Grammar)를 텍스트 파서로 만들어주는 파서 생성기이다. 현재 기준 깃헙 스타 수가 1,500에 육박한다. 모수가 많지 않은 클로저 바닥을 고려할 때 꽤 높은 수치다. 게다가 파서 생성기라는 주제는 대상이 한정적이라는 점까지 생각해보면 상당한 수다. 관심 있는 사람이 많다는 것은 나름 탄탄하게 믿고 쓸만할 가능성이 크다고 여길 수 있으니, 믿고 시간을 투자해보자.

그리고, 이건 클로저용 파서 생성기 이야기지만, 사실 파서 생성기 없는 프로그래밍 언어는 없을 테니, 어떤 프로그래밍 언어를 쓰더라도, 전체 맥락을 함께 이해하는 데는 큰 문제가 없을 것이다, 아마도.

아래는, 인스타파서의 소개문(?)이다.

What if context-free grammars were as easy to use as regular expressions?

만약 CFG를 쓰는 것이 정규표현식(regular expression)을 쓰는 것처럼 쉽다면? 으잉? 정규표현식이야 워낙 자주 편리하게 쓰니 익숙한데, CFG를 그렇게 쉽게 쓸 수 있다고? 그게 말이 되나? 이런 의심이 들면서도 혹해서, 이미 난 나머지 긴 설명을 읽고 있다.

Context-Free Grammar & Parsing Expression Grammar

읽어보니, EBNF나 ABNF표기를 써서 CFG 기반 파서를 만들어주는 것인데, PEG(Parsing Expression Grammar)의 몇몇 기능을 확장했다고 한다. 아, 이렇게 한 문장에 모르는 단어 많이 나오면 참 힘들다. 그래도, EBNF랑 CFG는 학창시절 들어본 용어인데, PEG는 들어 본적조차 없다.

CFG는 문서를 해독할 때 모호성(ambiguity)을 안고 가는데, 이것은 원래 CFG가 자연어 처리를 목적으로 만들었기 때문이다. 그러나, 기계를 대상으로 한 언어를 위한 경우에는 이것은 지나친 복잡도를 일으킨다. CFG로는 같은 텍스트로부터 다른 파스 트리들을 만들 수도 있는데, PEG는 애초에 우선순위를 두어 모호성을 미리 피해간다. 찾아보니, 다행히 PEG는 2004년의 논문으로 알려진 것 같고, 그러니 학창시절에는 배웠을 리 없는 내용이었다. 다행이다, 이 부분은 콤플렉스를 피해갔다.

예를 들어, 아래와 같은 CFG가 있다면,

S := A | B

규칙 S는 A도 되고, B도 된다. 그리고 만약 A 규칙과 B 규칙이 모두 매칭되면, 두 파스 트리를 구하게 된다. 그런데, PEG에서는,

S <- A / B

이렇게 / 표기로, 우선순위 있는 (prioritized, ordered) 선택을 표현한다. 먼저 A에 매칭을 시도하고, A 매칭이 실패해야만 B 매칭을 시도한다.

더 자세한 내용은 시간을 들여 공부해야할 것 같고, 요약하면 CFG의 모호성을 피해 기계 중심의 파서를 만들기 좋은 PEG가 있다는 거다.

인스타파서의 CFG와 PEG

가만 보니 인스타파서는 CFG와 PEG의 합작품이다. 기본은 CFG인데, PEG의 우선순위 선택과 미리보기(lookahead) 조건 기능이 있어서, 모호성을 피해 가는 선택을 할 수 있다. 필요하다면 CFG로 여러 파스 트리를 뽑을 수도 있고, PEG 확장 표기를 써서 우선순위와 조건으로 걸러낸 파스 트리를 뽑을 수도 있다.

복잡하게 돌아왔는데, 결론적으로 마크다운 문법은 모호하고, 단지 CFG로 해석해서 변환하기 어려울 수 있는데, 인스타파서에 있는 PEG 확장까지 곁들여 쓴다면, 문제없이 해석해서 입맛에 맞게 요리할 수 있을 것 같다.

클로저웨스트 컨퍼런스

이런 고민을 하는 요즘, 미국 시애틀에서는 클로저웨스트(Clojure/west) 컨퍼런스가 열렸다. 단 이틀간 하는 컨퍼런스이니 이제 끝났겠구나. 지인 두 명이나 참가했다는 소식을 접하고 참 부러워 했다. 해외 컨퍼런스에 다녀오면, 영어에 대한 압박을 받아 힘든 점도 있지만, 배울점을 많이 얻게되고 또 의욕도 충만해져서 돌아오게 되는 그 분위기가 너무 좋다. 직접 가지는 못해서 아쉽지만, 거의 발표 직후에 발표 동영상이 유튜브에 올라와서 간접적으로나마 즐거움을 누릴 수 있다. 좋은 세상이다.

그 중, 때마침 누군가가 인스타파서 말고 PEG 기반 파서를 만든 얘기를 발표했다. 이런 묘한 우연이란!

Parsing Text with a Virtual Machine — Ghadi Shayban

여기 보면, 앞부분에 어떨 때 왜 정규표현식이 아니라 복잡한 파서를 만들어야 하는지에 대한 설명도 있다.

다음 편에 계속

너무 어려운 내용을 많이 썼다. 다음 편에 인스타파서를 조금 더 공격적으로 써서, 마크다운 파서에 접근해 봐야겠다. 원하는 결과를 성공적으로 뽑아낼 수 있을지 살짝 두렵긴 해도, 어떻게든 되겠지. 뭐라도 배우고.

그럼, 언젠가 쓸 다음 편에 계속.

(추천을 누르면 다음 편이 빨리 올라옵니다. ㅎㅎ)


생각보다 많은 분이 추천을 눌러주셔서 다음편을 서둘러 썼씁니다. 이 글은 연재 중입니다.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.