EOS(End of String)でのRaku文法の停止


9

楽のDSL能力を習得するための言い訳として、ある音楽言語から別の言語(ABCからAlda)への翻訳者を書く過程で、.parse!を終了する方法がないようです。これが私の短いデモコードです:

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

そして、それは私の問題を示すGrammer :: Tracerディスプレイの最後の部分です。

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

2行目から最後の行で、FAILという単語は、.parse実行が終了する方法がないことを示しています。これは正しいのかしら?.sayはすべてを本来の形で表示するので、FAILがどれほど本物であるかはわかりません。「複数の行をエラーなしで解析する文法を正しく書くにはどうすればよいですか?」という疑問が残ります。


私はあなたの学習プロセスに干渉したくありませんが、あなたが気づいていない場合に備えて、ABCモジュールがあります
レイフ

1
ええと、少なくともテストするために同じ曲を選んだわけではありません!
hsmyers

回答:


10

文法デバッガーを使用すると、エンジンが文字列を解析する方法を正確に確認できます。失敗は正常で予期されるものです。たとえば、a+b*文字列との一致が考えられますaab。'a'の2つの一致が表示され、その後に失敗します(bisでないためa)が、再試行しbて正常に一致します。

これは、||(順序を強制する)を交互に実行すると、より簡単に確認できます。あなたが持っている場合

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

「I have a kiwi」という文を解析すると、最初に「I have a」と一致し、次に「apple」と「orange」で2つ失敗し、最後に「kiwi」と一致することがわかります。

今あなたのケースを見てみましょう:

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

ここでの失敗は正常です。ある時点で<score>トークンが不足するため、失敗は避けられません。これが発生すると、文法エンジンは、文法の後にあるものに移動でき<score>+ます。何もないので、失敗すると実際には文字列全体がTOP一致します(暗黙のと一致するため/^…$/)。

また、<。ws> *を自動的に挿入するルールで文法を書き換えることを検討することもできます(単一のスペースのみであることが重要でない限り)。

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

さらに、IMEでは、uc / lcのプロトトークンを追加することも[ <foo> | <bar> ]できます。これは、常に持っていると、それらの1つが未定義になり、アクションクラスでの処理が少し面倒になる可能性があるためです。あなたは試すことができます:

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

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

$<letter> 常にこのように定義されます。


これは、「FAIL」を使用しても、一致オブジェクトが「so」をtrueとして返したという事実を説明しています。私はそうだろうと思った。実際のプロジェクトに必要なトークンを追加することに戻ります;)
hsmyers

実際の文法は、<。ws> *を自動的に挿入することを好まないようです。おそらく<score>以外のレイヤーが含まれているためです。テクニックを頭に
かぶせる


必要のないコードをデバッグすることは嫌いです。それから、すべてに美学があります。実際の問題は、ABCがスペースについて気にしないということです。いくつかの例外がありますが、概して、それらはほとんどどこでも発生する可能性があります。「使用」のケースは、大きな数字の文字列のカンマのような読みやすさの問題です。問題を理解して最小限に抑えるまで、必要に応じて問題を再検討します。
hsmyers

1
hsmyers:ありがたいことに理解することprotoはそれほど難しくはありません。一度理解すれば、生活がとても簡単になります。
user0721090601
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.