ANTLR로 Kotlin 문법 파싱하기

Hyeongjin Song·2022년 11월 24일
0

antlr

목록 보기
1/1
post-thumbnail

프로그래밍 언어 전공 수업에서 과제를 진행했다.

우테코에 집중하느라 많은 시간을 쏟지는 못했지만, ANTLR의 핵심 파악을 목표로 최대한 이해하고자 노력했다.

처음 과제를 접했을 때는 꽤나 무서웠다. 처음 보는 두 언어인 ANTLR와 Kotlin의 문법을 둘다 알아야 한다는 것이 버거웠다. 더군다나 ANTLR는 그냥 언어도 아니고 프로그래밍 언어를 파싱하는 언어 아닌가! 그냥 언어도 어려운데 언어를 파싱하는 언어를 다루라니..
하지만 거대한 공포도 잠시, Kotlin은 기본 문법만 알면 되었고, ANTLR 역시 문법이 많이 어렵지는 않았기에 과제를 진행하는 데에는 큰 무리가 없는 듯 보였다.

하지만 그것은 나의 무지로부터 비롯된 오산이었다.
github에 있는 Kotlin의 antlr 문법은 Lexer와 Parser를 포함하면 1천 5백줄이 넘어갔고, Parser.g4에 포함된 모든 non-terminal을 따라가며 문법 구조를 해석하는 것은 과제 제출 기한이 1달인 것에 대해 충분히 납득할만 했다.

과제 후기

과제의 성패와는 별개로, ANTLR는 상당히 흥미로운 언어였다. 하지만 매우 어려운 언어임은 확실했다.
다른 언어들과는 다르게 머리가 좋아야 잘 할것만 같은 그런 느낌..?
c언어가 그렇듯, 언어의 문법이 다른 언어에 비해 비교적 쉽다면 프로그래머의 역량에 따라 그 결과물이 확연히 갈리는 것 같다는 생각이 들었고 이 ANTLR 역시 그런 것 같았다.

그렇기에 AST를 단 1개로 만드는 것이 목표라면 쉬운 문법을 가진 Koltin이라도 상당히 까다로웠다.
class, 함수, 변수 정의, for문, while문 등을 각각 정의하여 non-terminal들로 안을 채우는 것은 쉽지 않았다.
특히, 편의를 위해 non-terminal를 지나치게 범용성이 높게 설정한다면, 파싱이 제대로 이루어지지 않는 일은 다반사였다.

Expression :
		   | '(' Expression ')'
           | '{' Expreesion '}'
           | Expression*
           | loops
           | declaration
           | SingleName
           | (LETTER* DIGIT+)*
           ...
           ;
          

이렇게 하나의 Expression이라는 non-terminal에 범주가 명확하지 않은 non-terminal과 terminal들을 마구 섞어놓으면 파싱이 엉터리가 될 확률은 매우 높아졌다(경험담입니다).

하지만 그렇다고 너무 따로따로 정의한다면 언어가 파싱할 수 있는 경우를 모두 고려하기에는 코드가 길어지고 분석이 어려워질 것이다. 따라서 이 안에서 적절한 타협점을 찾아가는 과정이 필요했다. 이것이 이번 과제의 핵심이었다.

고민의 결과, 나에게 떠오른 꼼수(?)는 정의할 함수(class, for, while 등등)마다 non-terminal을 겹치지 않게 따로따로 설정하는 것이었다.
우리가 할 parsing은 언어 전체가 아니다. 그렇기에 모든 상황을 고려할 수 있을 정도의 대단한 파싱을 하지 않아도 된다. 그렇기 때문에 함수끼리의 지나치게 얽히고설킨 대단히 복잡한 경우들에 대해서 고려하지 않는 것은 완벽하지 않지만 최선인 셈이다.

package my.demo -> 패키지 따로 non-terminal 설정

import java.util.* -> 임포트 따로 ..

int main(){  -> 함수 따로 ..
	var x=10  -> 변수 따로 ..
}

non-terminal을 따로따로 구현했다면 언어의 flexibility는 떨어질 지 몰라도, 기본적인 문법 정도는 완벽하게 파싱할 수 있었을 것이다.

하지만, 나는 너무 늦게 그 사실을 알아버렸고 이미 나의 g4파일의 코드는 돌이킬 수 없을만큼 복잡해져 있었다...ㅠㅠ

내 목표는 동네 뒷산 등반인데, 등산을 배운답시고 에베레스트 등반하기를 검색해서 방한복을 잔뜩 껴입고 아이젠을 신고 간 셈이다. 동네 뒷산은 반팔에 반바지, 그리고 나이키 운동화가 더 적격인데 말이다.

이렇게보면 kotlin의 g4파일 github를 훔쳐본게 오히려 독이 된 것일지도...?

막막할 땐 완벽을 잠시 덜고, 최선에 집중하는 것을 고민하는 것도 중요하다는 것을 배워가며..

학점을 주고 배움을 취하는 나...

input

매우 간단한 input.kt 이다.

lexer and parser

파싱이 잘 이루어졌다. javac를 돌리고 기다리는 이 순간이 가장 떨린다...

result


나쁘지는 않은 것 같다!
사실 너무 간단한 input이라.. 그래도 결과가 잘 나왔다는 것이 뿌듯...!

profile
first in, last out

0개의 댓글

관련 채용 정보