在以下解析器中:
object Foo extends JavaTokenParsers {
def word(x: String) = s"\\b$x\\b".r
lazy val expr = (foo ~ (conjGuard ~> rep(conj ~ noun))) | foo
def noun = {println("noun"); word("noun")}
def conj = {println("conj"); word("and") }
def conjGuard = {println("conjGuard"); guard(conj) | f }
def f = {println("failure"); (" *".r) ~ failure("bad conj!")}
def foo = {println("foo"); word("foo")}
}
为什么以下示例打印出conj
作为最后一次打印输出?它来自哪里?
scala> Foo.parseAll(Foo.expr, "foo and noun")
foo
conjGuard
conj
conj
noun
conj
res71: Foo.ParseResult[java.io.Serializable] = [1.13] parsed:
(foo~List((and~noun)))
另外,为什么这个例子中没有foo
首先打印出来?
scala> Foo.parseAll(Foo.expr, "foo an3 noun")
conj
failure
foo
res72: Foo.ParseResult[java.io.Serializable] =
[1.5] failure: string matching regex `\z' expected but `a' found
foo an3 noun
^
答案 0 :(得分:2)
为什么[it]打印出
conj
作为最后一次打印输出?
您使用rep
组合器,它将尝试连续多次解析conj ~ noun
。因此,在解析foo and noun
之后,它将尝试再次解析conj
,conj
将失败,因为没有更多输入,并且rep
将不会失败并且只返回成功的解析
要尝试第二次无法解析conj
,必须再次请求conj
解析器,因此输出中的最后一个conj
另外,为什么在这个例子中不首先打印foo?
您使用def
(而不是val
或lazy val
)在您使用println
的任何地方定义了解析器,并(正确地)思考,否则您只能获得第一个{ {1}},但您与println
陷入同一陷阱:lazy val expr
中的第一个foo
,conjGuard
和conj
只会被评估一次。
将Foo.expr
替换为lazy val
,一切恢复正常。
为了更好地了解会发生什么,您可以使用def
解析器而不是log
:
println
例如:
object Foo2 extends JavaTokenParsers {
def word(x: String) = s"\\b$x\\b".r
def expr = (foo ~ (conjGuard ~> rep(conj ~ noun))) | foo
def noun = log(word("noun"))("noun")
def conj = log(word("and"))("conj")
def conjGuard = log(guard(conj) | f)("conjGuard")
def f = log((" *".r) ~ failure("bad conj!"))("failure")
def foo = log(word("foo"))("foo")
}
答案 1 :(得分:1)
为什么以下示例打印出最后一个打印输出?它来自哪里?
它再次尝试conj
(在rep(conj ~ noun)
中),因为可能需要将另一个重复添加到列表中。即使考虑到输入已经结束,对conj
的这个调用可能会返回一个解析器,该解析器在空输入时成功。
然而,这对我来说也是令人惊讶的。另外,在这个例子中,为什么不首先打印出来?