Menghentikan tata bahasa Raku di EOS (End of String)


9

Dalam proses menulis penerjemah dari satu bahasa musik ke yang lain (ABC ke Alda) sebagai alasan untuk mempelajari kemampuan Raku DSL, saya perhatikan bahwa sepertinya tidak ada cara untuk mengakhiri .parse! Ini kode demo singkat saya:

#!/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;

Dan itu adalah bagian terakhir dari tampilan Grammer :: Tracer yang menunjukkan masalah saya.

|  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
」

Pada baris kedua hingga terakhir, kata FAIL memberi tahu saya bahwa .parse run tidak memiliki cara untuk berhenti. Saya ingin tahu apakah ini benar? .Say menampilkan semuanya sebagaimana mestinya, jadi saya tidak jelas tentang seberapa nyata GAGAL itu? Pertanyaannya tetap, "Bagaimana cara saya menulis tata bahasa dengan benar yang mem-parsing beberapa baris tanpa kesalahan?"


Saya tidak ingin ikut campur dalam proses belajar Anda, tetapi kalau-kalau Anda tidak sadar, ada modul ABC .
raiph

1
Yah, setidaknya kami tidak memilih lagu yang sama untuk diuji!
hsmyers

Jawaban:


10

Ketika Anda menggunakan tata bahasa debugger, itu memungkinkan Anda melihat dengan tepat bagaimana mesin mengurai string - gagal adalah normal dan diharapkan. Dianggap, misalnya, cocok a+b*dengan string aab. Anda harus mendapatkan dua pertandingan untuk 'a', diikuti oleh gagal (karena btidak a) tetapi kemudian akan mencoba lagi bdan berhasil mencocokkan.

Ini mungkin lebih mudah dilihat jika Anda melakukan pergantian dengan ||(yang memberlakukan perintah). Jika Anda memiliki

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

dan Anda parsing kalimat "Saya punya kiwi", Anda akan melihatnya pertandingan pertama "Saya punya", diikuti oleh dua gagal dengan "apel" dan "oranye", dan akhirnya cocok dengan "kiwi".

Sekarang mari kita lihat kasus Anda:

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

Kegagalan di sini adalah normal: pada titik tertentu kita akan kehabisan <score>token, sehingga kegagalan tidak bisa dihindari. Ketika itu terjadi, mesin tata bahasa dapat beralih ke apa pun yang muncul setelah <score>+tata bahasa Anda. Karena tidak ada apa-apa, kegagalan itu sebenarnya menghasilkan kecocokan seluruh string (karena TOPcocok dengan implisit /^…$/).

Selain itu, Anda dapat mempertimbangkan untuk menulis ulang tata bahasa Anda dengan aturan yang menyisipkan <.ws> * secara otomatis (kecuali penting untuk hanya menjadi satu ruang saja):

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

Selanjutnya, IME, Anda mungkin ingin juga ingin menambahkan token proto untuk uc / lc, karena ketika Anda memilikinya [ <foo> | <bar> ]Anda akan selalu memiliki salah satu dari mereka yang tidak terdefinisi yang dapat membuat memprosesnya dalam kelas tindakan agak mengganggu. Kamu bisa mencoba:

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

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

$<letter> akan selalu didefinisikan dengan cara ini.


Ini menjelaskan fakta bahwa objek pertandingan kembali 'begitu benar bahkan dengan' GAGAL '. Saya pikir mungkin itu masalahnya; Saya akan kembali ke menambahkan token yang diperlukan untuk proyek nyata;)
hsmyers

Tata bahasa sebenarnya sepertinya tidak suka memasukkan <.ws> * secara otomatis; mungkin karena lapisan tambahan yang terlibat di luar <score>. Saran Anda untuk menggunakan proto terlihat bagus segera setelah saya dapat membungkus kepala saya di sekitar teknik ...
hsmyers


Saya benci memiliki kode yang tidak saya butuhkan — lebih banyak untuk debug, dan kemudian ada estetika dari semuanya! Masalah sebenarnya adalah bahwa ABC tidak peduli tentang ruang. Ada beberapa pengecualian, tetapi pada umumnya, mereka dapat terjadi hampir di mana saja. Kasus 'use' adalah masalah keterbacaan agak seperti koma dalam string digit besar. Saya akan meninjau kembali masalah yang diperlukan sampai saya memahami masalah dan telah menguranginya seminimal mungkin.
hsmyers

1
hsmyers: syukurlah pengertiannya prototidak terlalu sulit dan begitu Anda memahami itu membuat hidup Anda jauh lebih mudah.
user0721090601
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.