0

作为我研究的一部分,我正在尝试为某种语言编写解析器。目前,我无法让以下代码以我想要的方式工作:

private def _uw: Parser[UW] = _headword ~ _modifiers ~ _attributes ^^ {
  case hw ~ mods ~ attrs => new UW(hw, mods, attrs)
}

private def _headword[String] = "\".*\"".r | "[^(),]*".r

private def _modifiers: Parser[List[UWModifier]] = opt("(" ~> repsep(_modifier, ",") <~ ")") ^^ {
  case Some(mods) => mods
  case None       => List[UWModifier]()
}

private def _modifier: Parser[UWModifier] = ("[^><]*".r ^^ (RelTypes.toRelType(_))) ~ "[><]".r ~ _uw ^^ {
  case (rel: RelType) ~ x ~ (uw: UW) => new UWModifier(rel, uw)
}

private def _attributes: Parser[List[UWAttribute]] = rep(_attribute) ^^ {
  case Nil   => List[UWAttribute]()
  case attrs => attrs
}

private def _attribute: Parser[UWAttribute] = ".@" ~> "[^>.]*".r ^^ (new UWAttribute(_))

上面的代码只包含了语言的一部分,为了节省时间和篇幅,我不会对整个语言进行过多的详细介绍。_uw 方法应该解析一个由三部分组成的字符串,尽管只有第一部分必须存在于字符串中。

_uw 应该能够正确解析这些测试字符串:

test0
test1.@attr
"test2"
"test3".@attr
test4..
test5..@attr
"test6..".@attr
"test7.@attr".@attr
test8(urel>uw)
test9(urel>uw).@attr
"test10..().@"(urel>uw).@attr
test11(urel1>uw1(urel2>uw2,urel3>uw3),urel4>uw4).@attr1.@attr2

因此,如果词条以 开头和结尾",则双引号内的所有内容都被视为词条的一部分。所有以 开头的词.@,如果它们不在双引号内,都是词条的属性。

例如在 test5 中,解析器应该解析test5.为词条和attr属性。只是 .@ 被省略,并且之前的所有点都应该包含在词条中。

因此,在词条之后可以有属性和/或修饰符。顺序是严格的,所以属性总是在修饰符之后。如果有属性但没有修饰符,则直到所有内容都.@被视为词条的一部分。

主要问题是"[^@(]*".r。我尝试了各种创造性的替代方案,例如"(^[\\w\\.]*)((\\.\\@)|$)".r,但似乎没有任何效果。前瞻或后瞻甚至如何影响解析器组合器?我不是解析或正则表达式方面的专家,所以欢迎所有帮助!

4

1 回答 1

1

我认为"[^@(]*".r与您的问题无关。我看到这个:

private def _headword[String] = "\".*\"".r | "[^(),]*".r

这是第一件事_uw(顺便说一下,不建议在 Scala 中的名称中使用下划线),所以当它尝试 parsetest5..@attr时,第二个正则表达式将匹配所有它!

scala> "[^(),]*".r findFirstIn "test5..@attr"
res0: Option[String] = Some(test5..@attr)

所以剩下的解析器将一无所有。此外,第一个正则表达式_headword也有问题,因为.*将接受引号,这意味着这样的事情变得有效:

"test6 with a " inside of it..".@attr

至于前瞻和后瞻,它根本不影响解析器组合器。正则表达式匹配,或者不匹配——这就是解析器组合器关心的所有内容。

于 2012-02-22T20:21:12.023 回答