파싱혁명

본 논문은 Brzozowski 미분을 문맥 자유 문법에 확장하고, 이를 파서 조합자에 일반화한 두 가지 새로운 파싱 기법을 제안한다. 구현은 250줄 미만의 코드로 이루어졌으며, Scala와 Haskell 버전을 제공한다. 실험 결과, S-Expression을 수백만 토큰 수준으로 파싱하면서 실용적인 성능을 보였다.

파싱혁명

초록

본 논문은 Brzozowski 미분을 문맥 자유 문법에 확장하고, 이를 파서 조합자에 일반화한 두 가지 새로운 파싱 기법을 제안한다. 구현은 250줄 미만의 코드로 이루어졌으며, Scala와 Haskell 버전을 제공한다. 실험 결과, S-Expression을 수백만 토큰 수준으로 파싱하면서 실용적인 성능을 보였다.

상세 요약

이 논문은 전통적인 Yacc 기반 LALR 파서가 갖는 복잡성, 테이블 생성 비용, 그리고 문법 제한성을 극복하고자 한다. 첫 번째 접근법은 Brzozowski의 정규식 미분 개념을 문맥 자유 문법(CFG)으로 일반화한다는 점에서 혁신적이다. 기존 미분은 정규식의 언어를 한 심볼씩 소모하면서 남은 언어를 계산하는데, 이를 CFG에 적용하면 비터미널마다 현재 입력 심볼에 대한 파생 집합을 동적으로 계산할 수 있다. 이 과정은 재귀적이며, 메모이제이션을 통해 중복 계산을 방지한다. 결과적으로 파서는 입력 스트림을 한 번만 스캔하면서 파생 트리를 구축한다.

두 번째 접근법은 파서 조합자(parser combinators)와 미분을 결합한다. 파서 조합자는 함수형 언어에서 파서를 고차 함수로 표현하는 기법인데, 여기서는 각 조합자에 대해 미분 연산을 정의한다. 예를 들어, 시퀀스 조합자는 첫 번째 파서가 입력을 소비한 뒤 남은 입력에 대해 두 번째 파서를 미분한다. 이러한 정의는 파서 자체를 미분 가능한 객체로 만들며, 전체 파서는 입력 심볼에 따라 점진적으로 축소된다.

핵심적인 기술적 통찰은 “지연 파싱 포레스트(lazy parse forest)”를 활용한다는 점이다. 파서는 완전한 파싱 트리를 즉시 생성하지 않고, 필요할 때마다 서브트리를 평가한다. 이는 메모리 사용을 최소화하고, 모호한 문법에 대해 모든 파싱 결과를 효율적으로 보관한다. 또한, 구현 코드가 250줄 미만이라는 점은 이 기법이 복잡한 테이블 생성이나 상태 머신 설계 없이도 충분히 실용적임을 보여준다.

성능 평가에서는 S-Expression을 대상으로 수백만 토큰을 초당 파싱했으며, 이는 전통적인 LR 파서와 비교해 경쟁력 있는 수치다. 특히, Haskell 구현은 순수 함수형 특성을 살려 메모이제이션과 지연 평가를 자연스럽게 결합했으며, Scala 구현은 JVM 위에서 높은 처리량을 달성했다. 이러한 결과는 미분 기반 파싱이 이론적 흥미를 넘어 실제 시스템에 적용 가능함을 입증한다.

요약하면, 이 논문은 미분 연산을 CFG와 파서 조합자에 확장함으로써 파싱 복잡성을 크게 낮추고, 구현의 간결성, 메모리 효율성, 그리고 실행 성능을 동시에 달성한 혁신적인 접근법을 제시한다.


📜 논문 원문 (영문)

🚀 1TB 저장소에서 고화질 레이아웃을 불러오는 중입니다...