Dừng ngữ pháp Raku tại EOS (Kết thúc chuỗi)


9

Trong quá trình viết một dịch giả của một ngôn ngữ âm nhạc sang ngôn ngữ khác (ABC sang Alda) như một cái cớ để học khả năng DSL của Raku, tôi nhận thấy rằng dường như không có cách nào để chấm dứt a .parse! Đây là mã demo rút gọn của tôi:

#!/home/hsmyers/rakudo741/bin/perl6
use v6d;

# use Grammar::Debugger;
use Grammar::Tracer;

my $test-n01 = q:to/EOS/;
a b c d e f g
A B C D E F G
EOS

grammar test {
  token TOP { <score>+ }
  token score {
      <.ws>?
      [
          | <uc>
          | <lc>
      ]+
      <.ws>?
  }
  token uc { <[A..G]> }
  token lc { <[a..g]> }
}

test.parse($test-n01).say;

Và nó là phần cuối cùng của màn hình Grammer :: Tracer thể hiện vấn đề của tôi.

|  score
|  |  uc
|  |  * MATCH "G"
|  * MATCH "G\n"
|  score
|  * FAIL
* MATCH "a b c d e f g\nA B C D E F G\n"
「a b c d e f g
A B C D E F G
」

Trên dòng thứ hai đến dòng cuối cùng, từ FAIL cho tôi biết rằng chạy .parse không có cách nào để bỏ. Tôi tự hỏi nếu điều này là chính xác? .Ssay hiển thị mọi thứ như mong muốn, vì vậy tôi không rõ FAIL thực sự như thế nào? Câu hỏi vẫn còn là "Làm thế nào để tôi viết đúng một ngữ pháp phân tích cú pháp nhiều dòng mà không gặp lỗi?"


Tôi không muốn can thiệp vào quá trình học tập của bạn, nhưng chỉ trong trường hợp bạn không biết, có một mô-đun ABC .
raiph

1
Chà, ít nhất chúng tôi đã không chọn những giai điệu giống nhau để thử nghiệm!
hsmyer

Câu trả lời:


10

Khi bạn sử dụng trình gỡ lỗi ngữ pháp, nó cho phép bạn xem chính xác cách công cụ phân tích cú pháp chuỗi - thất bại là bình thường và được mong đợi. Được xem xét, ví dụ, phù hợp a+b*với chuỗi aab. Bạn sẽ nhận được hai trận đấu cho 'a', sau đó là thất bại (vì bkhông phải a) nhưng sau đó nó sẽ thử lại vớib và khớp thành công.

Điều này có thể dễ dàng nhìn thấy hơn nếu bạn thực hiện xen kẽ với ||(thực thi lệnh). Nếu bạn có

token TOP   { I have a <fruit> }
token fruit { apple || orange || kiwi }

và bạn phân tích câu "Tôi có một quả kiwi", bạn sẽ thấy nó khớp đầu tiên "Tôi có một", sau đó là hai lần thất bại với "quả táo" và "quả cam", và cuối cùng là trận đấu với "quả kiwi".

Bây giờ hãy xem trường hợp của bạn:

TOP                  # Trying to match top (need >1 match of score)
|  score             #   Trying to match score (need >1 match of lc/uc)
|  |  lc             #     Trying to match lc
|  |  * MATCH "a"    #     lc had a successful match! ("a")
|  * MATCH "a "      #   and as a result so did score! ("a ")
|  score             #   Trying to match score again (because <score>+)
|  |  lc             #     Trying to match lc 
|  |  * MATCH "b"    #     lc had a successful match! ("b")
|  * MATCH "b "      #   and as a result so did score! ("b ")
……………                #     …so forth and so on until…
|  score             #   Trying to match score again (because <score>+)
|  |  uc             #     Trying to match uc
|  |  * MATCH "G"    #     uc had a successful match! ("G")
|  * MATCH "G\n"     #   and as a result, so did score! ("G\n")
|  score             #   Trying to match *score* again (because <score>+)
|  * FAIL            #   failed to match score, because no lc/uc.
|
|  # <--------------   At this point, the question is, did TOP match?
|  #                     Remember, TOP is <score>+, so we match TOP if there 
|  #                     was at least one <score> token that matched, there was so...
|
* MATCH "a b c d e f g\nA B C D E F G\n" # this is the TOP match

Thất bại ở đây là bình thường: đến một lúc nào đó chúng ta sẽ hết <score>token, vì vậy một thất bại là không thể tránh khỏi. Khi điều đó xảy ra, bộ máy ngữ pháp có thể chuyển sang bất cứ thứ gì xuất hiện sau <score>+ngữ pháp của bạn. Vì không có gì, thất bại đó thực sự dẫn đến một trận đấu của toàn bộ chuỗi (vì TOPkhớp với ẩn/^…$/ ).

Ngoài ra, bạn có thể xem xét viết lại ngữ pháp của mình với quy tắc tự động chèn <.ws> * (trừ khi nó chỉ là một khoảng trắng duy nhất):

grammar test {
  rule TOP { <score>+ }
  token score {
      [
          | <uc>
          | <lc>
      ]+
  }
  token uc { <[A..G]> }
  token lc { <[a..g]> }
}

Hơn nữa, IME, bạn cũng có thể muốn thêm mã thông báo proto cho uc / lc, bởi vì khi bạn có, [ <foo> | <bar> ]bạn sẽ luôn có một trong số chúng không được xác định, điều này có thể khiến việc xử lý chúng trong lớp hành động hơi khó chịu. Bạn có thể thử:

grammar test {
  rule  TOP   { <score>  + }
  token score { <letter> + }

  proto token letter    {     *    }
        token letter:uc { <[A..G]> }
        token letter:lc { <[a..g]> }
}

$<letter> sẽ luôn được định nghĩa theo cách này.


Điều này giải thích thực tế rằng đối tượng phù hợp đã trả về 'vì vậy là đúng ngay cả với' FAIL '. Tôi nghĩ rằng đó có thể là trường hợp; Tôi sẽ quay trở lại để thêm các mã thông báo cần thiết cho dự án thực sự;)
hsmyer

Ngữ pháp thực tế dường như không thích tự động chèn <.ws> *; có lẽ do các lớp bổ sung liên quan vượt quá <điểm>. Gợi ý của bạn để sử dụng proto có vẻ tốt ngay khi tôi có thể quấn đầu xung quanh kỹ thuật này
hsmyer


Tôi ghét có mã mà tôi không cần nhiều hơn để gỡ lỗi, và sau đó có tính thẩm mỹ của tất cả! Vấn đề thực tế là ABC không cung cấp cho không gian chết tiệt. Có một số trường hợp ngoại lệ, nhưng nhìn chung, chúng có thể xảy ra ở hầu hết mọi nơi. Trường hợp 'sử dụng' là một vấn đề về mức độ dễ đọc giống như dấu phẩy trong các chuỗi chữ số lớn. Tôi sẽ xem xét lại vấn đề khi cần thiết cho đến khi tôi hiểu được vấn đề và đã giảm nó xuống mức tối thiểu.
hsmyer

1
hsmyer: rất may sự hiểu biết protokhông quá khó và một khi bạn hiểu rõ về nó, nó làm cho cuộc sống của bạn dễ dàng hơn rất nhiều.
user0721090601
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.