Scala PackratParsers:回溯似乎不起作用

时间:2014-07-28 02:35:01

标签: scala backtracking parser-combinators

以下scala代码无法按预期工作:

import scala.util.parsing.combinator.PackratParsers
import scala.util.parsing.combinator.syntactical.StandardTokenParsers
import scala.util.parsing.combinator.lexical.StdLexical

object Minimal extends StandardTokenParsers with PackratParsers {
  override val lexical = new StdLexical

  lexical.delimiters += ("<", "(", ")")

  lazy val expression: PackratParser[Any] = (
  numericLit
  | numericLit ~ "<" ~ numericLit
  )

  def parseAll[T](p: PackratParser[T], in: String): ParseResult[T] =
    phrase(p)(new PackratReader(new lexical.Scanner(in)))

  def main(args: Array[String]) = println(parseAll(expression, "2 < 4"))
}

我收到错误消息:

[1.3] failure: end of input expected

2 < 4
  ^

但是,如果我将“表达式”的定义更改为

  lazy val expression: PackratParser[Any] = (
    numericLit ~ "<" ~ numericLit
  | numericLit
  )

问题消失了。

问题似乎是,对于“表达式”的原始定义代码,应用了仅由“numericLit”组成的第一个规则,这样解析器确实希望输入在之后立即结束。我不明白为什么解析器一旦注意到输入确实没有结束就不会回溯; scala PackratParsers应该是回溯,我也确保用另一个问题的答案中的“lazy val”替换“def”。

2 个答案:

答案 0 :(得分:1)

您看到此行为的原因是交替运算符(垂直条)旨在接受其成功的第一个替代方案。在你的情况下numericLit成功,所以交替从不考虑其他选择。

使用这种语法规范,如果一个替代方案可以匹配另一个替代方案,则必须小心。正如您所见,更长的替代方案应该放在替代方案的早期,否则它永远不会成功。

如果您希望较短的替代选项仅在其后没有更多输入时匹配,那么您可以尝试使用not组合子来表达该额外条件。但是,如果要在其他构造中使用expression,则此方法将导致问题。

答案 1 :(得分:1)

它与packrat解析器无关。

您需要知道的是,在PEG中,选择运算符会选择第一个匹配项,在您的情况下为numericLit