тл; dr Я не знаю, как packrat может спасти вас от двух больших проблем, которые у вас есть. Это спасло меня от stackoverflow, но у меня не было такого вопиющего левого отказа.
Я имею в виду, что ваша рекурсия expr + expr
никогда не должна заканчиваться. Я так понимаю, что у вас где-то есть некая база индукции, т.е. expr = expr + expr | term
.
Теперь вы можете легко сделать правильную ассоциативность с помощью term + expr | term
для правильной ассоциативности, потому что, когда последний термин найден, вы глубоко под + рекурсией. Точно так же вы делаете левую ассоциативность expr + term | term
. Левая ассоциативная связь вызывает левую рекурсию, и вы никогда не достигаете конечного термина. От этого не спасает даже пакрат. Я не понимаю, как вы получаете свои результаты. Мой
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))
}
стек переполняется. Это спасло меня один раз, но у меня не было такого вопиющего левого отказа. И я не знаю, как это может спасти вас от второй проблемы, которую вы задаете.
В любом случае, вы должны устранить рекурсию, заменив 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)
person
Valentin Tihomirov
schedule
30.12.2015