LL과 LR 구문 분석의 차이점은 무엇입니까?


답변:


483

높은 수준에서 LL 구문 분석과 LR 구문 분석의 차이점은 LL 구문 분석기가 시작 기호에서 시작하여 대상 문자열에 도달하기 위해 프로덕션을 적용하려고하는 반면, LR 구문 분석기는 대상 문자열에서 시작하여 다시 시작합니다. 상징.

LL 구문 분석은 왼쪽에서 오른쪽으로, 가장 왼쪽에서 파생됩니다. 즉, 입력 심볼을 왼쪽에서 오른쪽으로 고려하여 가장 왼쪽 파생을 구성하려고 시도합니다. 이것은 시작 기호에서 시작하여 대상 문자열에 도달 할 때까지 가장 왼쪽의 비 터미널을 반복적으로 확장하여 수행됩니다. LR 구문 분석은 왼쪽에서 오른쪽으로 가장 오른쪽 파생입니다. 즉, 왼쪽에서 오른쪽으로 스캔하여 가장 오른쪽 파생을 구성하려고합니다. 파서는 지속적으로 입력의 하위 문자열을 선택하여 비 터미널로 되돌리려 고 시도합니다.

LL 구문 분석 중에 구문 분석기는 두 가지 조치 중에서 지속적으로 선택합니다.

  1. 예측 : 가장 왼쪽에있는 비 터미널 및 일부 예측 토큰을 기반으로 입력 문자열에 더 가깝게 적용 할 프로덕션을 선택합니다.
  2. Match : 가장 왼쪽에 추측 된 터미널 기호를 가장 왼쪽에있는 소비되지 않은 입력 기호와 일치시킵니다.

예를 들어,이 문법을 보면 :

  • S → E
  • E → T + E
  • E → T
  • T → int

그런 다음 string이 주어지면 int + int + intLL (2) 파서 (두 개의 lookahead 토큰을 사용)는 다음과 같이 문자열을 구문 분석합니다.

Production       Input              Action
---------------------------------------------------------
S                int + int + int    Predict S -> E
E                int + int + int    Predict E -> T + E
T + E            int + int + int    Predict T -> int
int + E          int + int + int    Match int
+ E              + int + int        Match +
E                int + int          Predict E -> T + E
T + E            int + int          Predict T -> int
int + E          int + int          Match int
+ E              + int              Match +
E                int                Predict E -> T
T                int                Predict T -> int
int              int                Match int
                                    Accept

각 단계에서 우리는 프로덕션에서 가장 왼쪽의 심볼을 봅니다. 터미널 인 경우 터미널과 일치하고 터미널이 아닌 경우 규칙 중 하나를 선택하여 터미널이 무엇인지 예측합니다.

LR 파서에는 두 가지 동작이 있습니다.

  1. Shift : 고려할 다음 입력 토큰을 버퍼에 추가합니다.
  2. 감소 : 생산을 반대로하여이 버퍼의 터미널 및 비 터미널 수집을 일부 비 터미널로 되돌립니다.

예를 들어, LR (1) 파서 (하나의 미리보기 토큰이있는)는 다음과 같은 문자열을 구문 분석 할 수 있습니다.

Workspace        Input              Action
---------------------------------------------------------
                 int + int + int    Shift
int              + int + int        Reduce T -> int
T                + int + int        Shift
T +              int + int          Shift
T + int          + int              Reduce T -> int
T + T            + int              Shift
T + T +          int                Shift
T + T + int                         Reduce T -> int
T + T + T                           Reduce E -> T
T + T + E                           Reduce E -> T + E
T + E                               Reduce E -> T + E
E                                   Reduce S -> E
S                                   Accept

언급 한 두 가지 파싱 알고리즘 (LL 및 LR)은 서로 다른 특성을 갖는 것으로 알려져 있습니다. LL 파서는 손으로 직접 작성하는 것이 쉽지만 LR 파서보다 강력하지 않으며 LR 파서보다 훨씬 작은 문법을 받아들입니다. LR 파서는 많은 맛 (LR (0), SLR (1), LALR (1), LR (1), IELR (1), GLR (0) 등)으로 제공되며 훨씬 강력합니다. 또한 훨씬 더 복잡한 경향이 있으며 거의 ​​항상 yacc또는 같은 도구로 생성됩니다 bison. LL 파서는 또한 ANTLR도구에 의해 사용되는 LL (*)를 포함하여 많은 풍미 가 있습니다. 실제로 LL (1)이 가장 널리 사용됩니다.

뻔뻔스러운 플러그 인으로서 LL 및 LR 파싱에 대해 더 배우고 싶다면 컴파일러 과정을 가르치고 과정 웹 사이트 에서 파싱 에 대한 유인물과 강의 슬라이드를 마쳤습니다 . 유용하다고 생각되면 그 중 하나를 자세히 설명해 드리겠습니다.


40
당신의 강의 슬라이드는 경이롭고 쉽게 본 가장 재미있는 설명입니다.
kizzx2

1
슬라이드에 대해서도 언급해야합니다! 지금 그들 모두를 겪고 있습니다. 많은 도움이됩니다! 감사!
kornfridge

정말 슬라이드를 즐기고 있습니다. 비 Windows 버전의 프로젝트 파일 (pp2의 scanner.l 파일)을 게시 할 수 있다고 생각하지 않습니까? :)
Erik P.

1
Matt의 탁월한 요약 답변에 기여할 수있는 한 가지는 LL (k) 구문 분석기로 구문 분석 할 수있는 모든 문법 (즉, 다음 구문 분석 조치를 결정하기 위해 "k"터미널을 찾고 있음)은 LR ( 1) 파서. 이것은 LL 파싱에 대한 LR 파싱의 놀라운 힘에 대한 힌트를 제공합니다. 출처 : LALR () 파서 제작자 인 F. DeRemer 박사가 가르치는 UCSC의 컴파일러 과정.
JoGusto

1
훌륭한 자원! 슬라이드, 유인물, 프로젝트를 제공해 주셔서 감사합니다.
P. Hinker

58

Josh Haberman은 그의 기사 LL과 LR Parsing Demystified 에서 LL 파싱은 폴란드 표기법 과 직접적으로 일치하고 LR은 역 폴란드 표기법 과 일치한다고 주장합니다 . PN과 RPN의 차이점은 방정식의 이진 트리를 순회하는 순서입니다.

방정식의 이진 트리

+ 1 * 2 3  // Polish (prefix) expression; pre-order traversal.
1 2 3 * +  // Reverse Polish (postfix) expression; post-order traversal.

Haberman에 따르면 이는 LL과 LR 파서의 주요 차이점을 보여줍니다.

LL 및 LR 파서의 작동 방식의 주요 차이점은 LL 파서가 구문 분석 트리의 사전 주문 순회를 출력하고 LR 파서가 주문 후 순회를 출력한다는 것입니다.

자세한 설명을 위해 예제와 결론은 Haberman의 기사를 확인 하십시오 .


9

LL은 하향식을 사용하고 LR은 상향식 접근 방식을 사용합니다.

프로그램 언어를 구문 분석하는 경우 :

  • LL은 소스 코드를보고, 여기에는 함수가 포함되고 표현식이 포함됩니다.
  • LR은 함수에 속하는 표현식을보고 전체 소스를 생성합니다.

6

LL 구문 분석은 LR과 비교할 때 장애가 있습니다. 다음은 LL 파서 생성기의 악몽 인 문법입니다.

Goal           -> (FunctionDef | FunctionDecl)* <eof>                  

FunctionDef    -> TypeSpec FuncName '(' [Arg/','+] ')' '{' '}'       

FunctionDecl   -> TypeSpec FuncName '(' [Arg/','+] ')' ';'            

TypeSpec       -> int        
               -> char '*' '*'                
               -> long                 
               -> short                   

FuncName       -> IDENTIFIER                

Arg            -> TypeSpec ArgName         

ArgName        -> IDENTIFIER 

FunctionDef는 ';'까지 정확히 FunctionDecl처럼 보입니다. 또는 '{'가 발견되었습니다.

LL 구문 분석기는 두 규칙을 동시에 처리 할 수 ​​없으므로 FunctionDef 또는 FunctionDecl을 선택해야합니다. 그러나 어느 것이 올바른지 알기 위해서는 ';' 또는 '{'. 문법 분석시, 예측 (k)은 무한한 것으로 보입니다. 구문 분석 시간에는 유한하지만 클 수 있습니다.

LR 파서는 두 규칙을 동시에 처리 할 수 ​​있으므로 미리 볼 필요가 없습니다. 따라서 LALR (1) 파서 생성기는이 문법을 쉽게 처리 할 수 ​​있습니다.

입력 코드가 주어지면 :

int main (int na, char** arg); 

int main (int na, char** arg) 
{

}

LR 파서는

int main (int na, char** arg)

';'가 나타날 때까지 어떤 규칙이 인식되는지 신경 쓰지 않고; 또는 '{'.

LL 구문 분석기는 인식되는 규칙을 알아야하기 때문에 'int'에서 끊어집니다. 따라서 ';'을 미리 봐야합니다. 또는 '{'.

LL 파서의 또 다른 악몽은 문법의 재귀입니다. 왼쪽 재귀는 문법에서 일반적인 것으로 LR 파서 생성기에는 문제가 없지만 LL은 처리 할 수 ​​없습니다.

따라서 LL을 사용하여 문법을 부 자연스럽게 작성해야합니다.


0

가장 왼쪽 파생 예 : 문맥이없는 문법 G는

z → xXY (규칙 : 1) X → Ybx (규칙 : 2) Y → bY (규칙 : 3) Y → c (규칙 : 4)

가장 왼쪽으로 파생 된 문자열 w = 'xcbxbc'를 계산합니다.

z ⇒ xXY (규칙 : 1) ⇒ xYbxY (규칙 : 2) ⇒ xcbxY (규칙 : 4) ⇒ xcbxbY (규칙 : 3) ⇒ xcbxbc (규칙 : 4)


가장 오른쪽 파생 예 : K → aKK (규칙 : 1) A → b (규칙 : 2)

가장 오른쪽 파생 된 문자열 w = 'aababbb'을 계산하십시오.

K ⇒ aKK (규칙 : 1) ⇒ aKb (규칙 : 2) ⇒ aaKKb (규칙 : 1) ⇒ aaKaKKb (규칙 : 1) ⇒ aaKaKbb (규칙 : 2) ⇒ aaKabbb (규칙 : 2) ⇒ aababbb (규칙 : 2)

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