EOS'da Raku dilbilgisini durdurma (Dizenin Sonu)


9

Raku DSL yeteneğini öğrenmek için bir bahane olarak bir müzik dilinin bir çevirmenini diğerine (ABC'den Alda'ya) yazma sürecinde, bir sonlandırmanın bir yolu olmadığını fark ettim .parse! İşte kısaltılmış demo kodum:

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

Ve sorunumu gösteren Grammer :: Tracer ekranının son kısmı.

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

İkinci son satırda, FAIL sözcüğü bana .parse çalıştırmasının bırakma yolunun olmadığını söyler. Acaba bu doğru mu? .Say her şeyi olması gerektiği gibi görüntüler, bu yüzden FAIL'in ne kadar gerçek olduğu konusunda net değil miyim? Soru, "Birden çok satırı hatasız ayrıştıran bir dilbilgisini nasıl doğru yazabilirim?"


Öğrenme sürecinize müdahale etmek istemiyorum, ancak farkında olmadığınız durumlarda bir ABC modülü var .
raiph

1
En azından test etmek için aynı ezgileri seçmedik!
hsmyers

Yanıtlar:


10

Dilbilgisi hata ayıklayıcısını kullandığınızda, motorun dizeyi nasıl ayrıştırdığını tam olarak görmenizi sağlar - başarısızlıklar normal ve beklenen bir durumdur. Örneğin, a+b*dize ile eşleştirme olarak düşünülür aab. 'A' için iki maç almanız ve ardından başarısız olmanız gerekir (çünkü bdeğildir a) ancak daha sonra yeniden dener bve başarıyla eşleşir.

Eğer ||(siparişi zorlar) ile bir değişiklik yaparsanız bu daha kolay görülebilir . Eğer varsa

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

ve "Ben bir kivim var" cümlesini ayrıştırırsınız, ilk maçta "Ben" var, ardından "elma" ve "portakal" ile iki başarısızlık ve son olarak da "kivi" ile bir eşleşme görürsünüz.

Şimdi davanıza bakalım:

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

Buradaki başarısızlık normaldir: bir noktada <score>belirteçler tükenir, bu nedenle başarısızlık kaçınılmazdır. Bu olduğunda, dilbilgisi motoru dilbilginizde gelen her şeye geçebilir <score>+. Hiçbir şey olmadığından, bu başarısızlık aslında tüm dizenin eşleşmesiyle sonuçlanır (çünkü TOPörtük olanlarla eşleşir/^…$/ ).

Ayrıca, dilbilginizi otomatik olarak <.ws> * ekleyen bir kuralla yeniden yazmayı düşünebilirsiniz (yalnızca tek bir boşluk olması önemli değilse):

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

Ayrıca, IME, uc / lc için bir proto jetonu da eklemek isteyebilirsiniz, çünkü sahip [ <foo> | <bar> ]olduğunuzda bunlardan her zaman tanımlanamayacaksınız, bu da onları bir eylem sınıfında işlemeyi biraz can sıkıcı hale getirebilir. Deneyebilirsiniz:

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

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

$<letter> her zaman bu şekilde tanımlanacaktır.


Bu, eşleşme nesnesinin geri döndüğü gerçeğini açıklar, 'BAŞARISIZ' ile bile doğrudur. Durumun böyle olabileceğini düşündüm; Gerçek proje için gerekli jetonları eklemeye geri döneceğim;)
hsmyers

Gerçek dilbilgisi otomatik olarak <.ws> * eklemeyi sevmez; muhtemelen <score> 'un ötesindeki ek katmanlar nedeniyle. Proto kullanma önerisi başımı tekniğin etrafına
doyabildiğim


İhtiyacım olmayan bir koddan nefret ediyorum - hata ayıklamak için daha çok, ve sonra her şeyin estetiği var! Asıl sorun, ABC'nin boşluklar hakkında bir lanet vermemesi. Bazı istisnalar vardır, ancak genel olarak neredeyse her yerde ortaya çıkabilirler. 'Kullanım' durumu, büyük rakam dizgilerindeki virgüller gibi okunabilirlik meselesidir. Sorunu anlayana ve en aza indirene kadar sorunu gerektiği gibi tekrar ziyaret edeceğim.
hsmyers

1
hsmyers: minnetle anlamak protoçok zor değil ve bir kez asmak hayatınızı çok daha kolay hale getirir.
user0721090601
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.