LR, SLR 및 LALR 파서의 차이점은 무엇입니까?


103

LR, SLR 및 LALR 파서의 실제 차이점은 무엇입니까? SLR과 LALR이 LR 파서의 유형이라는 것을 알고 있지만 파싱 테이블에 관한 한 실제 차이점은 무엇입니까?

그리고 문법이 LR, SLR 또는 LALR인지 어떻게 보여줄까요? LL 문법의 경우 구문 분석 테이블의 모든 셀에 여러 생산 규칙이 포함되어서는 안된다는 것을 보여 주면됩니다. LALR, SLR 및 LR에 대한 유사한 규칙이 있습니까?

예를 들어 문법이

S --> Aa | bAc | dc | bda
A --> d

LALR (1)이지만 SLR (1)은 아닙니까?


편집 (ybungalobill) : LALR과 LR의 차이점에 대해 만족스러운 답변을 얻지 못했습니다. 따라서 LALR의 테이블은 크기가 더 작지만 LR 문법의 하위 집합 만 인식 할 수 있습니다. 누군가 LALR과 LR의 차이점에 대해 더 자세히 설명해 주시겠습니까? LALR (1) 및 LR (1)은 대답에 충분합니다. 둘 다 1 개의 토큰 미리보기를 사용하며 둘 다 테이블 기반입니다! 어떻게 다릅니 까?


글쎄, 이것에 대한 적절한 답을 찾고 있어도, LALR (1)은 LR (1)의 약간의
수정일뿐입니다

답변:


64

SLR, LALR 및 LR 파서는 모두 정확히 동일한 테이블 기반 기계를 사용하여 구현할 수 있습니다.

기본적으로 구문 분석 알고리즘은 다음 입력 토큰 T를 수집하고 현재 상태 S (및 관련 예견, GOTO 및 축소 테이블)를 참조하여 수행 할 작업을 결정합니다.

  • SHIFT : 현재 테이블이 토큰 T에서 SHIFT라고 말하면 쌍 (S, T)이 구문 분석 스택으로 푸시되고 현재 토큰에 대해 GOTO 테이블이 말하는 내용에 따라 상태가 변경됩니다 (예 : GOTO (T) ), 또 다른 입력 토큰 T '를 가져오고 프로세스를 반복합니다.
  • REDUCE : 모든 상태에는 0, 1 또는 해당 상태에서 발생할 수있는 많은 감소가 있습니다. 구문 분석기가 LR 또는 LALR 인 경우 토큰은 상태에 대한 모든 유효한 감소에 대해 미리보기 세트에 대해 확인됩니다. 토큰이 문법 규칙 G = R1 R2 .. Rn에 대한 감소에 대한 미리보기 세트와 일치하면 스택 감소 및 시프트가 발생합니다. G에 대한 시맨틱 조치가 호출되고 스택이 n (Rn에서) 번 팝되고 쌍 ( S, G)가 스택으로 푸시되고 새 상태 S '가 GOTO (G)로 설정되고주기가 동일한 토큰 T로 반복됩니다. 파서가 SLR 파서 인 경우에는 최대 하나의 감소 규칙이 있습니다. 어떤 축소가 적용되는지 검색하지 않고도 축소 조치를 맹목적으로 수행 할 수 있습니다. SLR 파서 감소 여부; 이것은 각 주가 그와 관련된 감소의 수를 명시 적으로 기록하는지, 그리고 그 수는 어쨌든 실제로 L (AL) R 버전에 필요합니다.
  • 오류 : SHIFT 또는 REDUCE가 모두 불가능하면 구문 오류가 선언됩니다.

그래서 그들이 모두 같은 기계를 사용한다면, 요점은 무엇일까요?

SLR의 가치는 구현의 단순성입니다. 최대 하나가 있기 때문에 가능한 감소 검사를 통해 미리보기 세트를 스캔 할 필요가 없으며, 상태에서 SHIFT 종료가없는 경우 유일한 실행 가능한 조치입니다. 어떤 감소가 적용되는지 구체적으로 상태에 첨부 할 수 있으므로 SLR 구문 분석 기계가이를 찾을 필요가 없습니다. 실제로 L (AL) R 파서는 유용하게 더 큰 언어 집합을 처리하며, 구현할 추가 작업이 너무 적기 때문에 학문적 연습을 제외하고는 아무도 SLR을 구현하지 않습니다.

LALR과 LR의 차이점은 테이블 생성기 와 관련이 있습니다.. LR 파서 생성기는 특정 상태 및 정확한 예측 세트에서 가능한 모든 감소를 추적합니다. 모든 감소가 왼쪽 컨텍스트의 정확한 예측 세트와 연관되는 상태로 끝납니다. 이것은 다소 큰 상태 세트를 작성하는 경향이 있습니다. LALR 파서 생성기는 GOTO 테이블과 축소를위한 룩 헤드 세트가 호환되고 충돌하지 않는 경우 상태를 결합합니다. 이것은 LR이 구별 할 수있는 특정 심볼 시퀀스를 구별 할 수 없다는 대가로 상당히 적은 수의 상태를 생성합니다. 따라서 LR 파서는 LALR 파서보다 더 많은 언어 집합을 파싱 할 수 있지만 훨씬 더 큰 파서 테이블을 가지고 있습니다. 실제로, 상태 머신의 크기를 최적화 할 가치가있는 대상 언어에 충분히 가까운 LALR 문법을 찾을 수 있습니다.

따라서 세 가지 모두 동일한 기계를 사용합니다. SLR은 기계의 작은 부분을 무시할 수 있다는 점에서 "쉬운"것이지만 문제의 가치는 없습니다. LR은 광범위한 언어 집합을 구문 분석하지만 상태 테이블은 상당히 큰 경향이 있습니다. 따라서 LALR이 실용적인 선택이됩니다.

이 모든 것을 말했듯이, GLR 파서 는 더 복잡한 기계를 사용 하지만 정확히 동일한 테이블 (LALR에서 사용하는 더 작은 버전 포함)을 사용하여 컨텍스트없는 언어를 구문 분석 할 수 있다는 것을 아는 것이 좋습니다. 이것은 GLR이 LR, LALR 및 SLR보다 훨씬 강력하다는 것을 의미합니다. 표준 BNF 문법을 작성할 수 있다면 GLR은 이에 따라 구문 분석합니다. 기계의 차이점은 GLR이 GOTO 테이블 및 / 또는 미리보기 세트간에 충돌이있을 때 여러 구문 분석을 시도한다는 것입니다. (GLR이이 작업을 효율적으로 수행하는 방법은 순전히 천재적이지만이 게시물에는 적합하지 않습니다.)

저에게는 매우 유용한 사실입니다. 나는 프로그램 분석기를 구축하고 코드 변환기와 파서는 필요하지만 "흥미롭지 않다"; 흥미로운 작업은 파싱 된 결과로 수행하는 작업이므로 파싱 후 작업을 수행하는 데 중점을 둡니다. GLR을 사용하면 LALR 사용 가능한 형식으로 들어가기 위해 문법을 해킹하는 것에 비해 상대적으로 쉽게 작동하는 문법을 구축 할 수 있습니다. 이것은 C ++ 또는 Fortran과 같은 비 학문적 인 언어를 처리하려고 할 때 매우 중요합니다. 여기서는 전체 언어를 잘 처리하기 위해 문자 그대로 수천 개의 규칙이 필요하고 문법 규칙을 해킹하는 데 평생을 소비하고 싶지 않습니다. LALR (또는 LR)의 한계를 충족합니다.

유명한 예로, C ++는 LALR 파싱을하는 사람들에 의해 파싱하기 매우 어려운 것으로 간주됩니다. C ++는 C ++ 참조 설명서 뒷면에 제공된 거의 모든 규칙을 사용하여 GLR 기계를 사용하여 구문 분석하는 것이 간단합니다. (정확히 그런 파서를 가지고 있으며 바닐라 C ++뿐만 아니라 다양한 벤더 방언도 처리합니다. 이는 실제로 GLR 파서 인 IMHO를 사용하기 때문에 가능합니다.)

[2011 년 11 월 편집 : 모든 C ++ 11을 처리하도록 파서를 확장했습니다. GLR을 사용하면 훨씬 쉽게 할 수 있습니다. 2014 년 8 월 편집 : 이제 모든 C ++ 17을 처리합니다. 고장이 나거나 악화 된 것은 없지만 GLR은 여전히 ​​고양이의 야옹입니다.]


AFAIK C ++는 무한한 미리보기가 필요하기 때문에 LR로 구문 분석 할 수 없습니다. 따라서 LR로 구문 분석 할 수있는 해킹을 생각할 수 없습니다. 또한 LRE 파서는 유망하게 들립니다.
Yakov Galka

5
Bison == LALR을 사용하여 C ++를 구문 분석하는 데 사용되는 GCC. 상심을주는 사례 (예측, is-this-a-typename)를 처리하기 위해 항상 추가 goo로 파서를 보강 할 수 있습니다. 문제는 "해킹이 얼마나 고통 스러운가?"입니다. GCC의 경우 매우 고통 스럽지만 작동하게 만들었습니다. 그렇다고 GLR을 사용하는 것이 좋습니다.
Ira Baxter

GLR을 사용하는 것이 C ++에서 어떻게 도움이되는지 이해하지 못합니다. 유형 이름인지 아닌지 모르는 경우 구문 분석 방법을 모를뿐입니다. x * y;GLR을 사용하면 어떻게 도움이 될까요?
user541686

2
요점은 GLR 파서가 두 가지 구문 분석을 모두 생성 한다는 것입니다 (통합 구문 분석 "트리"(실제로 DAG)에서 "모호한 하위 트리"). 나중에 유지하려는 하위 트리를 확인할 수 있습니다. 우리의 C ++ 파서는이 문제와 관련하여 놀랍도록 간단합니다. 문제를 해결 하려고하지 않습니다 . 즉, 파싱과 함께 심볼 테이블 구성을 엉 키게 할 필요가 없으므로 파서와 C ++ 용 심볼 테이블 구성 모두 개별적으로 깨끗하고 결과적으로 많은 각각의 구축 및 유지 관리 할 수 있습니다.
아이라 박스터

18

LALR 파서는 LR 문법 내에서 유사한 상태를 병합하여 동등한 SLR 문법과 정확히 동일한 크기의 파서 상태 테이블을 생성합니다.이 테이블은 일반적으로 순수한 LR 파싱 테이블보다 훨씬 작은 크기입니다. 그러나 LALR이 되기에는 너무 복잡한 LR 문법의 경우 이러한 병합 상태로 인해 파서 충돌이 발생하거나 원래 LR 문법을 완전히 인식하지 못하는 파서를 생성합니다.

BTW, 여기 MLR (k) 구문 분석 테이블 알고리즘에서 이에 대해 몇 가지 언급합니다 .

추가

짧은 대답은 LALR 파싱 테이블이 더 작지만 파서 기계는 동일하다는 것입니다. 주어진 LALR 문법은 많은 중복 (거의 동일) 상태로 모든 LR 상태가 생성되는 경우 훨씬 더 큰 구문 분석 테이블을 생성합니다.

LALR 테이블은 유사한 (중복) 상태가 함께 병합되어 개별 상태가 인코딩하는 컨텍스트 / 예측 정보를 효과적으로 폐기하기 때문에 더 작습니다. 장점은 동일한 문법에 대해 훨씬 작은 구문 분석 테이블을 얻을 수 있다는 것입니다.

단점은 모든 LR 문법이 LALR 테이블로 인코딩 될 수 없다는 것입니다. 더 복잡한 문법은 더 복잡한 예견을 가지므로 단일 병합 상태 대신 두 개 이상의 상태가 발생하기 때문입니다.

주요 차이점은 LR 테이블을 생성하는 알고리즘이 상태에서 상태로의 전환 사이에 더 많은 정보를 전달하는 반면 LALR 알고리즘은 그렇지 않다는 것입니다. 따라서 LALR 알고리즘은 주어진 병합 상태가 실제로 둘 이상의 개별 상태로 남아 있어야하는지 여부를 알 수 없습니다.


3
+1 Honalee 아이디어가 마음에 듭니다. 내 G / L (AL) R 파서 생성기에는 이와 같은 시드가 있습니다. 최소한의 LALR 시스템을 생성하고 충돌이있는 상태를 분할하려고했지만 통과하지 못했습니다. 이것은 구문 분석 테이블 세트와 같은 최소 크기 "LR"을 생성하는 좋은 방법처럼 보입니다. 구문 분석 할 수있는 측면에서 GLR에 도움이되지는 않지만 GLR이 수행해야하는 병렬 구문 분석의 수를 줄일 수 있으며 유용 할 것입니다.
Ira Baxter

12

또 다른 답변 (YAA).

SLR (1), LALR (1) 및 LR (1)에 대한 파싱 알고리즘은 Ira Baxter가 말한 것과 동일
하지만 파서 생성 알고리즘으로 인해 파서 테이블이 다를 수 있습니다.

SLR 파서 생성기는 LR (0) 상태 머신을 생성하고 문법 (FIRST 및 FOLLOW 집합)에서 미리보기를 계산합니다. 이것은 단순한 접근 방식이며 LR (0) 상태 시스템에 실제로 존재하지 않는 충돌을보고 할 수 있습니다.

LALR 파서 생성기는 LR (0) 상태 머신을 생성하고 LR (0) 상태 머신 (터미널 전환을 통해)에서 미리보기를 계산합니다. 이것은 올바른 접근 방식이지만 때때로 LR (1) 상태 시스템에 존재하지 않는 충돌을보고합니다.

Canonical LR 파서 생성기는 LR (1) 상태 시스템을 계산하고 미리보기는 이미 LR (1) 상태 시스템의 일부입니다. 이러한 파서 테이블은 매우 클 수 있습니다.

최소 LR 파서 생성기는 LR (1) 상태 시스템을 계산하지만 프로세스 중에 호환 가능한 상태를 병합 한 다음 최소 LR (1) 상태 시스템에서 미리보기를 계산합니다. 이러한 파서 테이블은 LALR 파서 테이블과 크기가 같거나 약간 더 크기 때문에 최상의 솔루션을 제공합니다.

LRSTAR 10.0 은 문법에 필요한 모든 것을 C ++로 LALR (1), LR (1), CLR (1) 또는 LR (*) 파서를 생성 할 수 있습니다. LR 파서 간의 차이점을 보여주는 이 다이어그램 을참조하십시오.

[전체 공개 : LRSTAR는 내 제품입니다]


5

미리보기가없는 파서가 문법에 맞는 문자열을 행복하게 파싱한다고 가정합니다.

주어진 예제를 사용하여 문자열을 발견 dc하면 무엇을합니까? 이 문법에 의해 생성 된 유효한 문자열 S이기 때문에로 줄 dc입니까? 아니면 bdc그게 허용되는 문자열이기 때문에 구문 분석을 시도했을 수도 있습니다 .

인간으로서 우리는 답이 간단하다는 것을 알고 있으므로 방금 파싱했는지 여부를 기억하면됩니다 b. 하지만 컴퓨터는 어리 석습니다 :)

SLR (1) 파서는 LR (0)에 대한 추가 권한을 가지고있어 미리보기를 수행하기 때문에 어떤 양의 미리보기가이 경우에 수행 할 작업을 알려줄 수 없다는 것을 알고 있습니다. 대신 우리는 과거를 되돌아 볼 필요가 있습니다. 따라서 표준 LR 파서가 구출됩니다. 과거의 맥락을 기억합니다.

이 문맥을 기억하는 방법은 스스로를 훈련하고,를 만날 때마다 하나의 가능성 b으로 독서를 향한 길을 걷기 시작한다는 것 bdc입니다. 따라서 a를 볼 때 d이미 경로를 걷고 있는지 여부를 압니다. 따라서 CLR (1) 파서는 SLR (1) 파서가 할 수없는 일을 할 수 있습니다!

하지만 이제는 너무 많은 경로를 정의해야했기 때문에 기계의 상태가 매우 커집니다!

따라서 우리는 동일한 경로를 병합하지만 예상대로 혼란의 문제를 일으킬 수 있습니다. 그러나 우리는 크기를 줄이는 대신 위험을 감수 할 의향이 있습니다.

이것은 LALR (1) 파서입니다.


이제 알고리즘 방식으로 수행하는 방법.

위의 언어에 대한 구성 집합을 그릴 때 두 가지 상태에서 shift-reduce 충돌이 발생합니다. 이를 제거하기 위해 SLR (1)을 고려할 수 있습니다. SLR (1)은 후속 조치를 고려하여 결정을 내리지 만 여전히 불가능하다는 것을 알 수 있습니다. 따라서 구성 세트를 다시 그리지 만 이번에는 클로저를 계산할 때마다 추가되는 추가 프로덕션에 엄격한 팔로우가 있어야한다는 제한이 있습니다. 다음에 따라야 할 교과서를 참조하십시오.


이 정확하지 않습니다

4

SLR과 LR로 생성 된 파서 테이블의 기본적인 차이점은 축소 작업이 SLR 테이블에 대해 설정된 Follows를 기반으로한다는 것입니다. 이것은 지나치게 제한적일 수 있으며 궁극적으로 교대 근무 감소 충돌을 유발할 수 있습니다.

반면에 LR 파서는 실제로 축소되는 비 터미널을 따라갈 수있는 터미널 세트에 대한 결정 만 줄입니다. 이 터미널 세트는 종종 그러한 비 터미널의 Follows 세트의 적절한 서브 세트이므로 시프트 동작과 충돌 할 가능성이 적습니다.

이러한 이유로 LR 파서는 더 강력합니다. 그러나 LR 구문 분석 테이블은 매우 클 수 있습니다.

LALR 파서는 LR 파싱 테이블을 구축한다는 아이디어로 시작하지만 생성 된 상태를 결합하여 테이블 크기를 크게 줄입니다. 단점은 LR 테이블이 피할 수 있었던 일부 문법에 대해 약간의 충돌 가능성이 도입된다는 것입니다.

LALR 파서는 LR 파서보다 약간 덜 강력하지만 SLR 파서보다 여전히 강력합니다. YACC 및 기타 이러한 파서 생성기는 이러한 이유로 LALR을 사용하는 경향이 있습니다.

PS 간결함을 위해 위의 SLR, LALR 및 LR은 실제로 SLR (1), LALR (1) 및 LR (1)을 의미하므로 하나의 토큰 미리보기가 암시됩니다.


4

SLR 파서는 LALR (1) 파서가 인식 할 수있는 적절한 문법 하위 집합을 인식하며, 이는 차례로 LR (1) 파서가 인식 할 수있는 적절한 문법 하위 집합을 인식합니다.

이들 각각은 상태 머신으로 구성되며 각 상태는 입력을 구문 분석 할 때 문법의 생산 규칙 (및 각 위치)의 일부 집합을 나타냅니다.

SLR이 아닌 LALR (1) 문법 의 Dragon Book 예는 다음과 같습니다.

S → L = R | R
L → * R | id
R → L

이 문법의 상태 중 하나는 다음과 같습니다.

S → L•= R
R → L•

가능한 제작 각각 파서의 위치를 나타낸다. 마지막에 도달하고 축소를 시도 할 때까지 실제로 어떤 제작물이 있는지 알지 못합니다.

여기에서 파서는를 이동 =하거나 줄일 수 있습니다 R → L.

SLR 카메라 (일명 LR (0)) 파서는 다음 입력 기호가있는 경우는 확인하여 감소시킬 수 있는지 여부를 확인 할 후속 세트R(즉, 수행 할 수있는 문법의 모든 단말기의 설정 R). 이후 =이 세트에 또한 상기 SLR 파서 변속 감소 충돌 발생.

그러나 LALR (1) 파서는 R의 특정 생산 을 따를 수있는 모든 터미널 세트를 사용합니다 . 이는 $입력의 끝입니다. 따라서 충돌이 없습니다.

이전 주석가들이 언급했듯이 LALR (1) 파서는 SLR 파서와 동일한 수의 상태를가집니다. 예견 전파 알고리즘은 해당 LR (1) 상태에서 SLR 상태 프로덕션에 대한 예견을 고정하는 데 사용됩니다. 결과 LALR (1) 파서는 LR (1) 파서에없는 감소-감소 충돌을 도입 할 수 있지만 시프트-감소 충돌을 도입 할 수는 없습니다.

귀하의 예제 에서 다음 LALR (1) 상태는 SLR 구현에서 shift-reduce 충돌을 유발합니다.

S → b d•a / $
A → d• / c

이후의 기호 /는 LALR (1) 파서의 각 프로덕션에 대한 후속 집합입니다. SLR에서 follow ( A) 는를 포함하며 a, 이는 또한 이동할 수 있습니다.



-2

한 가지 간단한 대답은 모든 LR (1) 문법이 LALR (1) 문법이라는 것입니다. LALR (1)과 비교하여 LR (1)은 연관된 유한 상태 기계에 더 많은 상태를 가지고 있습니다 (상태의 두 배 이상). 이것이 LALR (1) 문법이 LR (1) 문법보다 구문 오류를 감지하는 데 더 많은 코드를 필요로하는 주된 이유입니다. 그리고이 두 가지 문법에 대해 알아야 할 또 하나의 중요한 점은 LR (1) 문법에서 갈등을 줄이거 나 줄일 수 있다는 것입니다. 그러나 LALR (1)에는 갈등을 줄이거 나 줄일 수있는 가능성이 더 많습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.