LL과 재귀 하강 파서의 차이점은 무엇입니까?


79

나는 최근에 파서 (언어 / 문맥없는 문법을위한)가 어떻게 작동하는지 스스로 가르치려고 노력하고 있으며, 한 가지를 제외하고는 대부분 이해가되는 것 같습니다. 특히 두 가지 주요 알고리즘이 LL 파서 (스택 / 파싱 테이블 사용)와 재귀 하강 파서 (간단히 재귀 사용 ) 인 LL (k) 문법 에주의를 집중 하고 있습니다 .

내가 볼 수있는 한, 재귀 하강 알고리즘은 모든 LL (k) 문법과 그 이상에서 작동하는 반면 LL 파서는 모든 LL (k) 문법에서 작동합니다. 그러나 재귀 하강 파서는 구현할 LL 파서보다 훨씬 간단합니다 (LL 파서가 LR 파서보다 간단 하듯이).

그래서 제 질문은 알고리즘 중 하나를 사용할 때 발생할 수있는 장점 / 문제는 무엇입니까? 동일한 문법 세트에서 작동하고 구현하기가 더 까다 롭다는 점을 감안할 때 재귀 하강보다 LL을 선택하는 이유는 무엇입니까?


이봐, 설명해 주시겠습니까? 당신 은 LL 파서 (스택 / 파싱 테이블 사용)와 재귀 하강 파서 (간단히 재귀를 사용)로 작성합니다. . 이 답변 은 모든 하향식 파서가 LL 파서임을 나타냅니다. 나는 혼동 해요
최대 Koretskyi을

2
@MaximKoretskyi 확실히 사실이 아닙니다. LL 파서는 하향식 파서의 하위 집합입니다.
Noldorin

감사합니다. 제 질문에 대한 답변을 게시 해 주시겠습니까?
Max Koretskyi

답변:


105

LL은 일반적으로 재귀 하강보다 더 효율적인 구문 분석 기술입니다. 실제로 순진한 재귀 하강 파서는 최악의 경우 실제로 O (k ^ n) (여기서 n 은 입력 크기)입니다. 메모 화 ( Packrat 구문 분석기 를 생성하는)와 같은 일부 기술 은이를 개선 할뿐만 아니라 구문 분석기에서 허용하는 문법 클래스를 확장 할 수 있지만 항상 공간 절충이 있습니다. LL 파서는 (내가 아는 한) 항상 선형 시간입니다.

반대로, 재귀 하강 파서가 LL보다 더 큰 클래스의 문법을 처리 할 수 ​​있다는 직감이 맞습니다. 재귀 하강은 LL (*) (즉, 무제한 예견) 인 모든 문법과 모호한 작은 문법 집합을 처리 할 수 ​​있습니다 . 재귀 하강은 실제로 PEG 또는 Parser Expression Grammar (s) 의 직접 인코딩 된 구현이기 때문 입니다. 특히, 분리 연산자 ( a | b)는 교환 적이 지 a | b않습니다 b | a. 즉, 같지 않음을 의미합니다 . 재귀 하강 파서는 각 대안을 순서대로 시도합니다. 경우에 따라서 a입력과 일치하는 경우, 심지어는 succede 할 b 것이다 입력을 일치. 이것은 매달려있는 것과 같은 고전적인 "가장 긴 일치"모호성을 허용합니다else 분리를 올바르게 주문하면 문제가 해결됩니다.

이 모든 것을 통해, 그 것이다 는 선형 시간에서 실행되도록 재귀 하강을 이용한 LL (K) 분석기를 구현하기. 이는 본질적으로 예측 세트를 인라인하여 각 구문 분석 루틴이 일정한 시간에 주어진 입력에 대해 적절한 생산을 결정하도록함으로써 수행됩니다. 불행히도 이러한 기술은 전체 문법 클래스가 처리되지 않도록합니다. 예측 파싱에 들어가면 댕글 링과 같은 문제 else를 더 이상 쉽게 해결할 수 없습니다.

LL이 재귀 하강보다 선택되는 이유는 주로 효율성과 유지 관리의 문제입니다. 재귀 하강 파서는 구현하기가 훨씬 더 쉽지만 그들이 나타내는 문법이 선언적 형태로 존재하지 않기 때문에 일반적으로 유지하기가 더 어렵습니다. 대부분의 사소하지 않은 파서 사용 사례는 ANTLR 또는 Bison과 같은 파서 생성기를 사용합니다. 이러한 도구를 사용하면 알고리즘이 직접 인코딩 된 재귀 하강 또는 테이블 기반 LL (k)인지는 실제로 중요하지 않습니다.

흥미롭게도 재귀 하강 방식을 따라 직접 인코딩 된 구문 분석 알고리즘이지만 모든 LALR 문법을 처리 할 수있는 recursive-ascent 도 살펴볼 가치가 있습니다 . 또한 재귀 하강 파서를 함께 구성하는 기능적인 방법 인 파서 결합 자도 살펴볼 것입니다.


2
내가 기대했던 응답이 아주 많았습니다! :) 거기에 모든 정보를 주셔서 감사합니다 (마지막 부분을 포함하여 내가 알지도 못했던 것). 이 답변에서 제시 한 모든 개념을 이해하기 전에 조금 더 읽어야 할 것입니다.하지만 당신은 확실히 제 질문에 대답하고 더 많은 연구를 위해 올바른 방향으로 저를 지적했습니다. 지금 내가 애매 모호한 가장 중요한 것은 PEG가 재귀 적 하강 파서와 어떻게 관련되는지 그리고 파서 결합기가 다양한 파서를 정확히 결합하는 방법입니다. 이 두 가지 중 하나를 명확히 할 수 있다면 매우 감사하겠습니다.
Noldorin 2009-06-25

6
예측 세트 : 실제로 사용되는 전략에 따라 다릅니다. 당신이 경우 에만 그 예측 세트에 의존하고 더 되돌아을 수행하지, 다음 문법의 클래스가 정확하게 k는이 세트를 예측 계산하는 데 사용 내다의 양을 LL (K)이다. 그러나 역 추적을 완전히 제거하지 않고 RD에서 예측 세트를 인라인하여 예측 구문 분석의 많은 이점을 얻을 수 있습니다. 이를 통해 RD에서 일반적으로 처리하는 모든 문법을 허용하지만 평균 사례가 더 빠른 구문 분석기를 사용할 수 있습니다. 불행히도 그러한 파서의 최악의 경우는 여전히 기하 급수적입니다.
Daniel Spiewak

5
대부분의 재귀 하강 파서 (손으로 작성한 파서 포함)는 인라인 예측 세트를 사용 하여 대체 항목 을 제한 하고 유연성을 제한하지 않고 역 추적을 제한합니다. 최종 결과는 가장 병리학적인 문법을 제외하고 모든 것에 대해 거의 선형 시간이며 여전히 전체 PEG 클래스를 허용하는 파서입니다.
Daniel Spiewak 2009-06-26

5
좋은 물건. 하지만 한 가지 요점 : "대부분의 사소한 사용 사례는 일종의 파서 생성기에서 구현됩니다 ...". 그건 사실이 아니야. 가장 널리 사용되는 컴파일러 및 IDE (C #, VB, Visual C ++ 및 GCC가 좋은 예임)는 수작업으로 작성된 파서를 사용합니다. 그것들은 틀림없이 가장 사소한 용도 중 일부입니다.
Scott Wisniewski

4
@DanielSpiewak 나는 당신이 몇 년 전에 그 댓글을 올렸다는 것을 알고 있지만 그 당시에도 그것은 틀렸다.) GCC는 3.x까지 C- 파서에 들소를 사용했지만 내가 할 수있는 한 2008 년에 손으로 쓴 재귀 하강 파서로 전환했다. 이에서에게 gcc.gnu.org/wiki/New_C_Parser
모르 텐 젠슨에게
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.