3

私は、音楽プログラミング言語のコードを取り、音楽イベント (音符、和音、音量/テンポの変更など) の解析ツリーを作成する PEG 文法に取り組んでいます。私の MPL の特徴は、音声、つまり同時に発生するさまざまなイベント シーケンスをサポートすることです。Instaparse文法でこれを正しく解析するのに苦労しています... 私が欲しいのは、 voices1 つ以上voiceの で構成されるタグで、それぞれが音声定義 (例: V1:) と任意の数のイベントで構成されます。voicesタグは、(V0:分割されたボイスの終わりを意味し、1 つのボイスまたは「ボイス ゼロ」に戻ることを意味します)、またはファイルの末尾で終了する必要があります。

以下は進行中の文法の抜粋です (わかりやすくするためにnote、 、 などの定義は省略しています)。chord

part                    = <ows> event+
<event>                 = chord | note | rest | octave-change |
                          attribute-change | voices |
                          marker | at-marker

voices                  = voice+ 
voice                   = !voices voice-number voice-events? 
                          (<voice-zero> | #"\z")
voice-number            = <"V"> #"[1-9]\d*" <":"> <ows>
<voice-zero>            = <"V0:"> <ows>
voice-events            = !voices event+ 

...

ows                     = #"\s*"

次のコードがあるとします。

V1: o2 b1/>b o2 g+/>g+ o2 g/>g 
V0: e8 f+ g+ a b2

パーサーを実行すると、次の出力が得られます。

[:part 
  [:voices 
    [:voice [:voice-number "1"] 
            [:voice-events 
              [:octave-change "2"] [:chord [:note [:pitch "b"] 
              [:duration "1"]] [:octave-change ">"] [:note [:pitch "b"]]] 
              [:octave-change "2"] [:chord [:note [:pitch "g+"]] 
              [:octave-change ">"] [:note [:pitch "g+"]]] 
              [:octave-change "2"] [:chord [:note [:pitch "g"]]
              [:octave-change ">"] [:note [:pitch "g"]]]]]] 
  [:note [:pitch "e"] [:duration "8"]] 
  [:note [:pitch "f+"]] 
  [:note [:pitch "g+"]] 
  [:note [:pitch "a"]] 
  [:note [:pitch "b"] [:duration "2"]]]

これはまさに私が欲しいものです。はタグのV0:終わりを示しvoices、最後の 5 つのノートはタグ内に単独で存在しpartます。

ただし、をに変更するV0V2、次のようになります。

[:part 
  [:voices 
    [:voice [:voice-number "1"] 
            [:voice-events 
              [:octave-change "2"] [:chord [:note [:pitch "b"] [:duration "1"]] 
              [:octave-change ">"] [:note [:pitch "b"]]] [:octave-change "2"] 
              [:chord [:note [:pitch "g+"]] [:octave-change ">"] 
              [:note [:pitch "g+"]]] [:octave-change "2"] 
              [:chord [:note [:pitch "g"]] [:octave-change ">"] 
              [:note [:pitch "g"]]] 
              [:voices 
                [:voice [:voice-number "2"] 
                [:voice-events 
                  [:note [:pitch "e"] [:duration "8"]] [:note [:pitch "f+"]] 
                  [:note [:pitch "g+"]] [:note [:pitch "a"]] 
                  [:note [:pitch "b"] [:duration "2"]]]]]]]]]

何らかの理由で、voice1 タグまたはそのvoice-eventsタグのいずれかが想定どおりに終了せず、2 番目のタグが最初の のvoice一部として飲み込まれます。また、2 番目のタグを付けたくありません。2 はプライマリタグ内にある必要があります。voicevoice-eventsvoicesvoicevoices

私が欲しいのはこれです:

[:part 
  [:voices 
    [:voice [:voice-number "1"] 
            [:voice-events 
              [:octave-change "2"] [:chord [:note [:pitch "b"] [:duration "1"]] 
              [:octave-change ">"] [:note [:pitch "b"]]] [:octave-change "2"] 
              [:chord [:note [:pitch "g+"]] [:octave-change ">"] 
              [:note [:pitch "g+"]]] [:octave-change "2"] 
              [:chord [:note [:pitch "g"]] [:octave-change ">"] 
              [:note [:pitch "g"]]]]]
    [:voice [:voice-number "2"] 
            [:voice-events 
              [:note [:pitch "e"] [:duration "8"]] [:note [:pitch "f+"]] 
              [:note [:pitch "g+"]] [:note [:pitch "a"]] 
              [:note [:pitch "b"] [:duration "2"]]]]]]

何が間違っているのかわかりませんが、voiceタグやタグを定義する方法に関係があると思いますvoice-events。それは私が否定的な先読みをどのように使用しているかに関係しているかもしれませんが、それはまだ完全には理解していないと思います. 文法を修正する方法を誰かが理解できますか?

ありがとう!:)

解決しました!

ありがとう、@DanielNeal! 私はこれに文法を作り直しました。これはまさに私が望むように機能します:

part                    = <ows> (voices | event)+
<event>                 = chord | note | rest | octave-change |
                          attribute-change | marker | at-marker

voices                  = voice+ (<voice-zero> | <#"\z">)
voice                   = voice-number event*
voice-number            = <"V"> #"[1-9]\d*" <":"> <ows>
<voice-zero>            = <"V0:"> <ows>

...

ows                     = #"\s*"

大きな変化は、私が と を定義する方法にpartありeventました。以前は、これらの用語をvoicesイベントとして定義していたため、後続voiceの はすべて消費され、前voiceのにまとめられていましたevent。anvoicesの定義を取り除き、可変数のグループ化またはs になるようeventに再定義することで、あいまいさを排除し、文法が希望どおりに動作するようにしました。partvoicesevent

その後、events内のは適切にグループ化されましたが、すべてのボイスを同じグループ内に配置する必要がある場合、voice各ボイスが個別のタグ内にあることにまだ問題がありました。タグが aまたはファイルの末尾 ( ) で終わるように指定することで、これを修正しました。つまり、タグが消費するコードの量をより具体的に指定します。voicesvoicesvoices"V0:"\zvoices

この話の教訓は、もしあなたが PEG 文法を書いていて問題を抱えているなら、おそらく定義があいまいでないようにする必要があるということです! また、否定的な先読みをまったく使用しないことになりました。これは、文法を単純化/曖昧さを解消するのに大いに役立ったと思います。

4

1 に答える 1