tl; dr packrat が、あなたが抱えている 2 つの大きな問題からどのように救えるのかわかりません。それは私をstackoverflowから救いましたが、そのような露骨な左の反省はありませんでした。
つまり、再帰expr + expr
は決して終了してはなりません。どこかに誘導の基盤があることを理解していますexpr = expr + expr | term
。
term + expr | term
最後の項が見つかったときは + 再帰の奥深くにいるため、 for 右結合によって簡単に右結合を作成できます。同様に、左結合性を作成しますexpr + term | term
。左結合は左再帰を引き起こし、最終項には決してなりません。packrat でさえ、そこから保存しません。どのように結果が得られるのか理解できません。私の
object EP extends JavaTokenParsers with PackratParsers {
def expr: Parser[_] = expr ~ ("+" ~> expr) | ident /*^^ {
case ident ~ rest => (ident /: rest){case (acc, e) => acc + s" + (${e.toString})"}
} | ident*/
}
List("a", "a + b", "a + b + c+ d") foreach {input =>
println("left: " + EP.parseAll(EP.expr, input))
}
スタックオーバーフロー。それは私を一度救いましたが、私はそのような露骨な左の反省を持っていませんでした. そして、あなたが尋ねる2番目の問題からどのようにあなたを救うことができるかわかりません.
とにかく、次のように変更expr + term | term
する再帰を排除する必要があります
def left: Parser[_] = ident ~ appendix
def appendix = "+" ~> left | ""
しかし、ident が再び最初のノードであることがわかるので、これは正しい再帰です。
解決策:したがって、すべての人が行うことを使用するだけです。rep
左から反復可能なリストを提供するパーサーを使用します。
def right: Parser[_] = ident ~ ("+" ~> right) ^^ {case head ~ tail => s"Right($head, $tail)"} | ident
lazy val left: Parser[_] = ident ~ rep("+" ~> ident) ^^
{case head ~ tail => (head /: tail){case (acc, expr) => s"Left($acc, $expr)"}}
println("right => " + parseAll(right, "a + b + c+ d"))
println("left => " + parseAll(left, "a + b + c+ d"))
生産する
right => [1.13] parsed: Right(a, Right(b, Right(c, d)))
left => [1.13] parsed: Left(Left(Left(a, b), c), d)