2019년 12월 13일 금요일

Crafting Interpreters - 6. Parsing Expressions 를 읽고

http://craftinginterpreters.com/parsing-expressions.html

앞장에서 문법을 어떻게 표현할 것인지를 살펴보고 간단한 문법을 Context-free grammar로 표시해 봤습니다.

이러한 문법 표현에서 모호함(ambiguity)이 있을 수 있습니다. 예를 들면, 1 + 2 * 3 의 경우 결과가 어떻게 나와야 할까요? 앞에서 부터 계산을 하면 결과는 9가 될 것이고, 곱하기를 먼저 한다면(우리가 수학에서 배웠듯이) 결과가 7이 될 겁니다.

이러한 모호함을 우선 순위(precedence)와 결합 법칙(associativity)을 정해서 해결할 수 있습니다.(또는 먼저 계산되어야 하는 값에 괄호를 사용할 수도 있을 겁니다.)

토큰을 분석(parsing)하는 방법에는 여러가지 방법이 있는데 여기서는 Recursive descent parsing을 살펴볼 겁니다. 파서를 만드는 가장 간단한 방법이지만 그렇다고 만만하게 볼 파서는 아닙니다. 실제로 GCC나 V8(JavaScript)이나 Roslyn(C#)등에서 사용되고 있거든요.

토큰을 분석하다 에러를 만나면 어떻게 하는 것이 좋을까요? 처음으로 만나는 에러에서 멈추고 그 부분을 표시해주는게 좋을까요? 이게 가장 간단한 방법이기도 하지요. 하지만, 사용자한테는 매번 에러가 나타날 때마다 바로바로 표시해 주는 것보다는 전체에서 발생할 수 있는 에러를 한번에 표시해주는게 좋을겁니다. 이걸 error recovery라고 부릅니다.

에러가 발생해도 계속 진행하면서 이후의 에러도 확인하려면 어떻게 해야 할까요? 에러가 발생한 지점부터 특정 지점까지는 무시했다가 그 다음부터 토큰 분석을 다시 시작해야 할겁니다. 안그러면 엄청나게 쓸데없는 에러가 표시되겠지요. 에러가 발생하면 파서는 바로 panic mode로 들어가고 다시 정상적으로 파싱을 시작할 수 있는 지점을 만나면 panic mode를 벗어나게 됩니다. 이러한 과정을 synchronizaion이라고 합니다.

댓글 없음:

댓글 쓰기

Building asynchronous views in SwiftUI 정리

Handling loading states within SwiftUI views self loading views View model 사용하기 Combine을 사용한 AnyPublisher Making SwiftUI views refreshable r...