Arresto della grammatica di Raku su EOS (End of String)


9

Nel processo di scrittura di un traduttore di una lingua musicale in un'altra (da ABC ad Alda) come scusa per imparare l'abilità DSL di Raku, ho notato che non sembra esserci un modo per terminare un .parse! Ecco il mio codice demo abbreviato:

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

Ed è l'ultima parte del display Grammer :: Tracer che dimostra il mio problema.

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

Nella penultima riga, la parola FAIL mi dice che la corsa .parse non ha modo di uscire. Mi chiedo se sia corretto? Il .say mostra tutto come dovrebbe essere, quindi non sono chiaro su quanto sia reale il FAIL? La domanda rimane: "Come posso scrivere correttamente una grammatica che analizza più righe senza errori?"


Non voglio interferire nel tuo processo di apprendimento, ma nel caso in cui non fossi a conoscenza, c'è un modulo ABC .
raiph,

1
Beh, almeno non abbiamo scelto gli stessi brani su cui provare!
hsmyers,

Risposte:


10

Quando si utilizza il debugger grammaticale, consente di vedere esattamente come il motore sta analizzando la stringa: i guasti sono normali e previsti. Considerato, ad esempio, l'abbinamento a+b*con la stringa aab. Dovresti ottenere due corrispondenze per "a", seguite da un errore (perché bnon lo è a) ma poi riproverà be corrisponderà correttamente.

Questo potrebbe essere visto più facilmente se si fa un'alternanza ||(che rafforza l'ordine). Se hai

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

e tu analizzi la frase "I have a kiwi", la vedrai prima abbinare "I have a", seguita da due errori con "apple" e "orange", e infine una corrispondenza con "kiwi".

Ora diamo un'occhiata al tuo caso:

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

Il fallimento qui è normale: a un certo punto finiremo i <score>token, quindi un fallimento è inevitabile. Quando ciò accade, il motore grammaticale può passare a qualsiasi cosa venga dopo la <score>+tua grammatica. Dal momento che non c'è nulla, quel fallimento in realtà si traduce in una corrispondenza dell'intera stringa (perché TOPcorrisponde a implicita /^…$/).

Inoltre, potresti considerare di riscrivere la tua grammatica con una regola che inserisce automaticamente <.ws> * (a meno che non sia importante che sia un solo spazio):

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

Inoltre, IME, potresti voler aggiungere anche un proto token per uc / lc, perché quando lo avrai [ <foo> | <bar> ]ne avrai sempre uno indefinito che può rendere un po 'fastidioso elaborarli in una classe di azioni. Puoi provare:

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

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

$<letter> sarà sempre definito in questo modo.


Questo spiega il fatto che l'oggetto match è tornato "così è vero anche con" FAIL ". Ho pensato che potrebbe essere il caso; Tornerò ad aggiungere i token necessari per il vero progetto;)
hsmyers il

Alla grammatica reale non sembra piacere inserire automaticamente <.ws> *; probabilmente a causa di ulteriori livelli coinvolti oltre <score>. Il tuo suggerimento di usare proto sembra buono non appena sono in grado di avvolgere la testa intorno alla tecnica ...
hsmyers,


Odio avere il codice di cui non ho bisogno, più per il debug e poi c'è l'estetica di tutto! Il vero problema è che ABC non se ne frega niente degli spazi. Ci sono alcune eccezioni, ma nel complesso, possono verificarsi quasi ovunque. Il caso "use" è una questione di leggibilità in qualche modo simile alle virgole nelle stringhe a grandi cifre. Rivisiterò il problema secondo necessità fino a quando non capirò il problema e lo ridurrò al minimo.
hsmyers,

1
hsmyers: per fortuna capire protonon è troppo difficile e una volta capito, ti semplifica la vita.
user0721090601
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.