Trình phân tích cú pháp gốc đệ quy với quay lui cho ngữ pháp


10

Ai đó có thể khai sáng cho tôi lý do tại sao một trình phân tích cú pháp gốc đệ quy với quay lui thử các sản phẩm và (theo thứ tự đó) không nhận ra ngôn ngữ được tạo bởi ngữ pháp .SmộtSmộtSmộtmộtSmộtSmột | mộtmột

Nó dường như chỉ phân tích các từ trong ngôn ngữ .{một2n | n1}

Tôi đã tạo một trình phân tích cú pháp như vậy bằng cách sử dụng Trình tạo phân tích cú pháp ABNF này với quy tắc sản xuất S = "a" S "a" / "aa"và trình phân tích cú pháp không nhận ra từ đó aaaaaa, ví dụ.

Tôi hy vọng nó sẽ sử dụng sản xuất cho đến khi nối các nút đầu cuối của cây parse từ bên trái bắt đầu bằng 7 , và sau đó đi lên cây parse chọn sản phẩm thay cho đến khi cây trông như thế điều này:SmộtSmộtaSmộtmột

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

2
Tại sao bạn nghĩ rằng nó không thể phân tích từ này?
Yuval Filmus

@Yuval, tôi nghĩ nó nên phân tích nó, vì vậy tôi phải thiếu một cái gì đó.
meribold

Ah, bây giờ câu hỏi có ý nghĩa hơn; cảm ơn đã chỉnh sửa! Nếu những gì bạn viết là đúng (tôi đã không kiểm tra) thì trình tạo dường như có lỗi. (Hoặc nó không phải là quy định về ngữ pháp của bạn, tôi nghĩ rằng đây là khó xảy ra kể từ khi ngữ pháp là tiểu học và rõ ràng.
Raphael

@Raphael, tôi chỉnh sửa lại câu hỏi (hy vọng không thay đổi ý nghĩa). Tôi thực sự được giao nhiệm vụ giải thích tại sao một trình phân tích cú pháp như vậy không nhận ra từ này aaaaaa.
meribold

Nơi mà bạn đã có được cây đó. Tôi không nhận được nhiều từ trình tạo trình phân tích cú pháp ABNF đó. Cây bạn cho không có nhiều ý nghĩa. Nhưng chuỗi aaaaaanên phân tích và không. Nhưng aaaakhông phân tích cú pháp. Bạn rõ ràng đúng về quyền hạn của 2. Điều phải được xử lý. nó chỉ phân tích cú pháp aavới S = "aa" / "a" [S] "a". Bạn có thể theo dõi những gì trình phân tích cú pháp làm?
babou

Câu trả lời:


6

Đây không phải là nhiều câu trả lời, nhưng cây phân tích không phù hợp với các bình luận bình thường.

Ngữ pháp của bạn nên phân tích chuỗi a a a a a a .SmộtSmột | mộtmộtmộtmộtmộtmộtmộtmột

Nhưng cây phân tích có dạng sau:

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

hoặc nếu bạn thích bản trình bày này, với các thiết bị đầu cuối trên các dòng khác nhau

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

Tôi đã kiểm tra rằng trình tạo trình phân tích cú pháp ABNF dường như không hoạt động, nhưng tôi không biết làm thế nào để theo dõi những gì nó làm.

Nó thực sự có vẻ như thu lại tập hợp không phải là những gì ngữ pháp định nghĩa.{một2n | n1}

Có một chút ngạc nhiên khi có một trang web phức tạp như vậy xung quanh một trình phân tích cú pháp lỗi, hơn nữa sử dụng một kỹ thuật phân tích cú pháp hoàn toàn không thú vị.


Sau khi xem xét thêm về nó:

Tôi nghĩ rằng tôi đã tìm thấy một nguồn của vấn đề. Dấu ngoặc vuông có nghĩa là tùy chọn .

Vì vậy, ngữ pháp của bạn nên được viết S = "a" S "a" / "aa" hoặc S = "a" [S] "a". Sau đó, nó dường như hoạt động chính xác.

Nhưng hệ thống rõ ràng bị mất khi có hai lần cùng một quy tắc trong các hình thức khác nhau. Tôi không chắc tại sao.

Tôi không tìm thấy một trang giải thích các vấn đề cú pháp này để chỉ định ngữ pháp.

Tôi vẫn xem xét lỗi đó.


1
Ôi. Vâng. Tôi không biết tôi đã nghĩ gì khi tôi viết cây phân tích đó. Tôi sẽ chỉnh sửa câu hỏi của tôi và dán câu hỏi của bạn.
meribold

Tôi đã tìm thấy một trình tạo phân tích cú pháp đệ quy, quay ngược lại với một bản demo trực tuyến ở đây và nó cho thấy hành vi tương tự với quy tắc này:S ::= 'a'<S>'a' | 'a''a'
meribold

Nó vẫn không phân tích cú pháp aaaaaakhi sử dụng S = "a" S "a" / "aa", nhưng bạn có vẻ đúng về dấu ngoặc.
meribold

Tôi không thấy điểm khám phá đệ quy gốc, trình phân tích cú pháp quay lui.
babou

bạn nói đúng S = "a" S "a" / "aa"... Tôi đã kiểm tra quá nhanh và nhấp vào tạo thay vì phân tích cú pháp.
babou

3

s1()SmộtSmộttrues()s2()Smộtmột

Xem xét phân tích từ aaaaaamột lần nữa. Tại một thời điểm, cây phân tích sẽ trông như thế này:

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

s()trueSSmộtmột

   S 
 / | \
a  S  a
  / \
 a   a

Mặc dù vậy, tôi có xu hướng coi đây là một vấn đề với việc triển khai của mình chứ không phải với các trình phân tích cú pháp gốc đệ quy nói chung.

#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

Đây là một tính năng không phải là một lỗi

Có một cái nhìn cận cảnh về thời điểm & nơi quay lui xảy ra:

     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

Điểm cốt yếu ở đây là trình phân tích cú pháp quay lại sau vị trí, nơi tìm thấy ký tự khớp cuối cùng. Đó là lý do tại sao nó "nhảy" từ cây 11 với l = aaaaaaaa sang cây thứ 12 với l = aaaa bằng cách sử dụng S -> aa tại l [7].


Cuối cùng cũng có thời gian để chỉnh sửa nó! ;)
Sabbas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.