parsing - 在 EOS(字符串结尾)处停止 Raku 语法

标签 parsing grammar raku

在编写一种音乐语言到另一种音乐语言的翻译器(ABC 到 Alda)的过程中,作为学习 Raku DSL 能力的借口,我注意到似乎没有办法终止 。解析!这是我缩短的演示代码:

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

在倒数第二行,“FAIL”一词告诉我 .parse 运行无法退出。我想知道这是否正确? .say 显示了应有的所有内容,所以我不清楚 FAIL 的真实性如何?问题仍然是,“如何正确编写一个语法来解析多行而不出错?”

最佳答案

当您使用语法调试器时,它可以让您准确地看到引擎如何解析字符串 - 失败是正常的,也是预料之中的。例如,考虑匹配 a+b*与字符串 aab 。您应该获得 'a' 的两个匹配项,然后失败(因为 b 不是 a ),但随后它将使用 b 重试。并成功匹配。

如果您与 || 进行交替,可能会更容易看到这一点(强制执行命令)。如果你有

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

当你解析句子“I have a kiwi”时,你会看到它首先匹配“I have a”,然后是“apple”和“orange”两次失败,最后是“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 添加一个原始 token ,因为当您有 [ <foo> | <bar> ] 时您总是会遇到其中一个未定义的情况,这可能会使在操作类中处理它们有点烦人。您可以尝试:

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

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

$<letter>将始终以这种方式定义。

关于parsing - 在 EOS(字符串结尾)处停止 Raku 语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59483099/

相关文章:

java - 如何使用 Jackson 将 JSON 数组中的嵌套值解析到列表中

ANTLR 用于可选键值

raku - 当使用 nextsame 或 callame 时,奇怪的 "Can' t use unknown trait

perl - Perl6 或 Perl5 是否有 Bottle 或 Sinatra 的等价物?

ruby - 是否有迭代编写新程序的程序?

multithreading - Perl6 多线程问题

python - 如何使用 lxml 访问评论

parsing - 人们用像antlr javacc这样的解析器做什么?

php - HTML 解析器获取元素之间的内容

grammar - 为什么LL语法不能是左递归的?