문법 대한 역 추적 기능이있는 순환 재귀 파서


10

누군가가 와 (순서대로) 를 시도하는 역 추적 기능이있는 재귀 적 하강 파서가 문법 의해 형성된 언어를 인식하지 못하는 이유를 누군가에게 ?S a a S a S a | SaSaSaaSaSa | aa

언어의 단어 만 구문 분석하는 것으로 보입니다 .{a2n | n1}

예를 들어 생산 규칙 과 함께이 ABNF 파서 생성기 를 사용하여 이러한 파서를 생성 S = "a" S "a" / "aa"했지만 파서는 단어를 인식하지 못합니다 aaaaaa.

왼쪽에서 구문 분석 트리의 터미널 노드가 연결될 때까지 프로덕션 를 사용 하고 트리가 보일 때까지 대신 프로덕션 를 선택하여 구문 분석 트리로 이동합니다. 이:S a aSaSaaSaa

   S 
 / | \
a  S  a
 / | \
a  S  a
  / \
 a   a

2
왜이 단어를 파싱 할 수 없다고 생각합니까?
Yuval Filmus

@ Yuval, 나는 그것을 파싱해야한다고 생각하므로 무언가를 놓치고 있어야합니다.
meribold

아, 이제 질문이 더 의미가 있습니다. 편집 해 주셔서 감사합니다! 당신이 쓰는 것이 사실이라면 (확인하지 않았습니다) 발전기에 버그가있는 것 같습니다. (또는 귀하의 문법에 대해서는 명시되어 있지 않습니다; 나는 문법이 기초적이고 모호하지 않기 때문에 이것이 불가능하다고 생각합니다.
Raphael

@Raphael, 나는 질문을 다시 편집했습니다 (의미를 바꾸지 않고). 나는 실제로 그러한 파서가 단어를 인식하지 못하는 이유를 설명해야합니다 aaaaaa.
meribold

그 나무는 어디서 났어? 그 ABNF 파서 생성기에서 많이 얻지 못했습니다. 당신이주는 나무는별로 이해가되지 않습니다. 그러나 문자열 aaaaaa은 파싱해야하며 그렇지 않습니다. 그러나 aaaa파싱합니다. 당신은 2의 거듭 제곱에 대해 분명히 옳습니다. 그것은 단지 구문 분석 aa과 함께 S = "aa" / "a" [S] "a". 파서의 기능을 추적 할 수 있습니까?
babou

답변:


6

이것은 많은 대답은 아니지만 구문 분석 트리는 일반적인 주석과 맞지 않습니다.

문법 는 문자열 구문 분석해야합니다 .a a a a a aSaSa | aaaaaaaa

그러나 구문 분석 트리의 형식은 다음과 같습니다.

      S 
     /|\
    / S \
   / /|\ \
  / / S \ \
 / / / \ \ \
a a a   a a a

또는 다른 회선에 터미널이있는이 프리젠 테이션을 선호하는 경우

     S 
   / | \
  a  S  a
   / | \
  a  S  a
    / \
   a   a

ABNF 파서 생성기가 작동하지 않는지 확인했지만 그 기능을 추적하는 방법을 모르겠습니다.

실제로 집합은 집합을 인식하는 것 같습니다 . 이는 문법이 정의하는 것이 아닙니다.{a2n | n1}

버그가 많은 파서 주변에 정교한 사이트가 있다는 것은 놀랍습니다.이 사이트는 완전히 흥미없는 파싱 기술을 사용합니다.


자세히 살펴본 후 :

문제의 원인 중 하나를 찾았습니다. 대괄호는 선택 사항을 의미 합니다.

따라서 문법은 S = "a" S "a" / "aa" 또는 로 작성해야합니다 S = "a" [S] "a". 그런 다음 제대로 작동하는 것 같습니다.

그러나 다른 형태의 동일한 규칙을 두 배로 사용하면 시스템이 손실됩니다. 왜 그런지 잘 모르겠습니다.

문법을 지정하는 데 필요한 구문 문제를 설명하는 페이지를 찾지 못했습니다.

나는 아직도 그 버기를 고려합니다.


1
아야. 네. 파싱 ​​트리를 작성할 때 내가 무슨 생각을했는지 모르겠습니다. 질문을 편집하고 붙여 넣을 것입니다.
meribold

나는 데모 온라인으로 파서 생성기를 역 추적, 다른 재귀 하강을 발견했다 여기에 과이 규칙과 동일한 동작을 보여줍니다S ::= 'a'<S>'a' | 'a''a'
meribold

aaaaaa사용할 때 여전히 구문 분석하지 않지만 S = "a" S "a" / "aa"대괄호에 대한 것 같습니다.
meribold

나는 재귀 하강, 역 추적 파서를 탐구하는 요점을 보지 못합니다.
babou

당신은 맞습니다 S = "a" S "a" / "aa"... 너무 빨리 테스트하고 구문 분석 대신 생성을 클릭했습니다.
babou

3

나는이 파서를 매우 간단하게 C ++로 작성했으며 (아래 참조) 동일한 문제가 있습니다. 이 될 것으로 보인다 때문에 때마다 기능 s1()생산을위한 반환 , 즉시 반환하고 시도하지 않는다 (구현하는 기능을 파스 트리의 노드를).S a aSaSatrues()s2()Saa

단어를 aaaaaa다시 구문 분석 하십시오. 어느 시점에서 구문 분석 트리는 다음과 같습니다.

   S 
 / | \
a  S  a
 / | \
a  S  a    <--
 / | \
a  S  a
  / \
 a   a

그런 다음, s()반환 true에 대한 S3 차원에서 -node 및 생산 결과 대신 한 단계 높은 여기서 고려되지 않습니다,하지만 :Saa

   S 
 / | \
a  S  a
  / \
 a   a

그래도 일반적으로 재귀 적 하강 파서를 역 추적하는 것이 아니라 내 구현 에서이 문제를 고려하는 경향이 있습니다.

#include <iostream>

char* next;    
bool term(char token) {
    if (*next != '\0')
        return *next++ == token;
    else
        return false;
}

bool s();    
bool s1() {
    return term('a') && s() && term('a');
}    
bool s2() {
    return term('a') && term('a');
}    
bool s() {
    auto save = next;
    return s1() or (next = save, s2());
}    

int main(int argc, char* argv[]) {
    next = "aaaaaa";
    if (s() && *next == '\0') {
        std::cout << "match";
    }
    else
        std::cout << "no match";
}

2

버그가 아닌 기능입니다

역 추적이 언제 어디서 발생하는지 자세히 살펴보십시오.

     1.           2.          3.          4.          5.          6.          7.          8.          9.          10.         11.         12.

     S            S           S           S           S           S           S           S           S           S           S           S      
   / | \        / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \
  a  S  a      a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a
                / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       /   \
               a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a     a
                            / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \       / | \
                           a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a
                                        / | \       / | \       / | \       / | \       / | \       / | \       / | \       /   \
                                       a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a     a
                                                    / | \       / | \       / | \       / | \       / | \       /   \
                                                   a  S  a     a  S  a     a  S  a     a  S  a     a  S  a     a     a
                                                                / | \       / | \       / | \       /   \   
                                                               a  S  a     a  S  a     a  S  a     a     a
                                                                            / | \       /   \
                                                                           a  S  a     a     a



w[] = 'aaaaaa'  //input
l[] = ''        //current tree leafs


 1. tree:   The parser starts with the start symbol S and tries first alternative S->aSa:       Result: w[0]  = l[0]     w = aaaaaa    l = aSa
 |          -- S->aSa works                                                                         | |     | | 
 6. tree:   The parser matches a after a:                                                       Result: w[6]  = l[6]     w = aaaaaa    l = aaaaaaSaaaaaa
 7. tree:   The parser tries S->aSa again but there is no match!                                Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaSaaaaaaa 
 8. tree:   The parser tries S->aa but there is still no match!                                 Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaaaaaaaa
 9. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaaaaaa
10. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaaaa
11. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaaaaaa
12. tree:   Backtracking after the last symbol that matched => Backtracking at l[7]             Result: w[7] != l[7]     w = aaaaaa    l = aaaa

여기서 중요한 점은 파서가 마지막 일치하는 문자를 찾은 위치 뒤에서 역 추적한다는 것입니다. 그와 트리 (11)로부터 "점프"의 이유 = L AAAAAAAA을 가진 12 트리 L = aaaa를 사용하여 > AA - S L [7] 위치에있다.


마침내 편집 할 시간이 생겼습니다! ;)
Sebbas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.