在Child Parser中使用`err`

时间:2014-08-05 20:35:30

标签: scala parser-combinators

在下面的Parser中:

object Foo extends JavaTokenParsers { 

  def word(x: String) = s"\\b$x\\b".r

  lazy val expr  = aSentence | something

  lazy val aSentence = noun ~ verb ~ obj

  lazy val noun   = word("noun")
  lazy val verb   = word("verb") | err("not a verb!")
  lazy val obj    = word("object")

  lazy val something = word("FOO")
}

它会解析noun verb object

scala> Foo.parseAll(Foo.expr, "noun verb object")
res1: Foo.ParseResult[java.io.Serializable] = [1.17] parsed: ((noun~verb)~object)

但是,在输入有效的noun但无效的verb时,为什么err("not a verb!")会使用该特定错误消息返回Error?< / p>

scala> Foo.parseAll(Foo.expr, "noun vedsfasdf")
res2: Foo.ParseResult[java.io.Serializable] =
[1.6] failure: string matching regex `\bverb\b' expected but `v' found

noun vedsfasdf
     ^

信用:感谢Travis Brown解释了对word函数here的需求。

question似乎相似,但我不确定如何使用err函数处理~

1 个答案:

答案 0 :(得分:3)

这是您可能会问的另一个问题:为什么它没有抱怨它期待“&#34; FOO&#34;但得到了&#34;名词&#34;?毕竟,如果它无法解析aSentence,那么它将尝试something

当你想到它时,罪魁祸首应该是显而易见的:源代码中有两个Failure结果并选择一个? |(又名append)。

Parser上的此方法会将输入提供给两个解析器,然后在append上调用ParseResult。该方法在该级别是抽象的,并以SuccessFailureError以不同方式定义。

SuccessError上,它始终采用this(即左侧的解析器)。但是,在Failure上,它还有其他功能:

case class Failure(override val msg: String, override val next: Input) extends NoSuccess(msg, next) {
  /** The toString method of a Failure yields an error message. */
  override def toString = "["+next.pos+"] failure: "+msg+"\n\n"+next.pos.longString

  def append[U >: Nothing](a: => ParseResult[U]): ParseResult[U] = { val alt = a; alt match {
    case Success(_, _) => alt
    case ns: NoSuccess => if (alt.next.pos < next.pos) this else alt
  }}
}

或者,换句话说,如果双方都失败了,那么它将占据阅读大部分输入的一方(这就是为什么它不会抱怨丢失FOO),但是如果两者都读取了相同的数量,它将优先于第二次失败。

我确实不知道它是否应该检查正确方面是否为Error,如果是,则返回该值。毕竟,如果侧是Error,它总是返回。这看起来很可疑,但也许它应该是那样的。但我离题了。

回到问题,似乎它应该与err一起消失,因为它们都消耗了相同数量的输入,对吧?嗯......这就是事情:正则表达式解析器首先跳过whiteSpace,但正则表达式文字和文字字符串。它不适用于所有其他方法,包括err

这意味着err的输入位于空白处,而单词的输入位于单词处,因此,输入位于输入处。试试这个:

lazy val verb   = word("verb") | " *".r ~ err("not a verb!")

可以说err应该被RegexParsers覆盖以做正确的事(tm)。由于Scala Parser Combinators现在是一个单独的项目,我建议您打开一个问题并使用Pull Request实施更改。它会对某些解析器产生更改错误消息的影响(嗯,这就是改变它的全部目的:)。