私はこの問題を自分自身で見つめていましたが、これはおそらく本当に愚かな質問になるでしょう。しかし私は私の誇りを飲み込む必要があります。スカラコンビネータパーサーは、私が思ったようにバックトラッキングしていません...
私はそれが思ったようにバックトラックしないこのコンビネーターパーサを持っています。私は文脈を完全に取り除かずに小さな例に減らしてきました。 「foobar」のような感覚は、読みにくいです。ここで私は行く:
@RunWith(classOf[JUnitRunner])
class ParserBacktrackTest extends RegexParsers with Spec with ShouldMatchers {
override def skipWhitespace = false
lazy val optSpace = opt(whiteSpace)
lazy val number = """\d+([\.]\d+)?""".r
lazy val numWithOptSpace = number <~ optSpace
private def litre = numWithOptSpace <~ ("litre" | "l")
def volume = litre ^^ { case _ => "volume" }
private def namedPieces = numWithOptSpace <~ ("pcs") ^^ { case _ => "explPcs" }
private def implicitPieces = number ^^ { case _ => "implPcs" }
protected def unitAmount = namedPieces | implicitPieces
def nameOfIngredient = ".*".r
def amount = volume | unitAmount
// def amount = unitAmount
protected def ingredient = (amount <~ whiteSpace) ~ nameOfIngredient
describe("IngredientParser") {
it("should parse volume") {
shouldParse("1 litre lime")
}
it("should parse explicit pieces") {
shouldParse("1 pcs lime")
}
it("should parse implicit pieces") {
shouldParse("1 lime")
}
}
def shouldParse(row: String) = {
val result = parseAll(ingredient, row)
result match {
case Success(value, _) => println(value)
case x => println(x)
}
result.successful should be(true)
}
}
だから何が起こることは3番目のテストが失敗したということです。
(volume~lime)
(explPcs~lime)
[1.4] failure: string matching regex `\s+' expected but `i' found
1 lime
^
だから、litre-parser
はリットルを消費し、それがどのスペースを見つけることができなかったとき、それが失敗したようです。しかし、私はそれが逆戻りして次の生産ルールを試みると思っていたでしょう。明らかにimplicitPieces
パーサは、この行を解析し、私は(コメントを削除する)前のボリュームパーサーを削除した場合、それは
(implPcs~litre lime)
(explPcs~lime)
(implPcs~lime)
が成功するためになぜamount
後戻りはないでしょうか?私は何を誤解していますか?
私はちょうどそれを得ることはありませんか?私はそれが失敗したときに後退することができなければならないということです。非バックトラッキングCFGパーサーはあまり価値がないでしょう。私はこれが動作することを意味します: '{def foo =" foo "; def bar = "bar"; def baz = "baz"; def foobarbaz = foo〜bar〜baz; def foobarfoo = foo〜bar〜foo; def p = foobarbaz | foobarfoo; ( "foobarに-パーサ")記述foobarbaz'が失敗この例では、{ それ( "それを解析する必要があり"){ shouldParseWith(P、 "foobarfoo") } }} ' –
@hedefalk'ので、 '| '代替案を試みる。あなたの質問では、 'volume'は成功しているので、' | 'は代替を試みません。 –
はい、これは私が表示しようとしていたものです。 @hedefalk:文法の細かい部分だけを書き直すだけで済むようにすることが重要です。ダニエルが言ったように、 'a |右手側は、左手側が失敗した場合にのみ評価され、これはあなたの手術ではそうではありません。 1つ以上のルールを並べ替えることができるかどうかを確認して、必要な優先順位を取得します。 – fotNelton