以下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”。
答案 0 :(得分:1)
您看到此行为的原因是交替运算符(垂直条)旨在接受其成功的第一个替代方案。在你的情况下numericLit
成功,所以交替从不考虑其他选择。
使用这种语法规范,如果一个替代方案可以匹配另一个替代方案,则必须小心。正如您所见,更长的替代方案应该放在替代方案的早期,否则它永远不会成功。
如果您希望较短的替代选项仅在其后没有更多输入时匹配,那么您可以尝试使用not
组合子来表达该额外条件。但是,如果要在其他构造中使用expression
,则此方法将导致问题。
答案 1 :(得分:1)
它与packrat解析器无关。
您需要知道的是,在PEG中,选择运算符会选择第一个匹配项,在您的情况下为numericLit
。