【问题标题】:scala parser combinator stackoverflow recursionscala解析器组合器stackoverflow递归
【发布时间】:2012-10-04 06:12:16
【问题描述】:

以下代码示例在解析嵌套在括号中的表达式时由于堆栈溢出而崩溃。

解析器组合器是标准库的一部分。有没有办法利用图书馆避免这种情况?

(我不是在问它崩溃的原因,而是在问处理标准库的正确方法。)

解析: (((((((((... 1 + 1 ...)))))))))

代码:

import scala.util.parsing.combinator.syntactical.StandardTokenParsers

object ArithmeticParser1 extends StandardTokenParsers {   
  lexical.delimiters ++= List("(", ")", "+", "-", "*", "/")

  val reduceList: Int ~ List[String ~ Int] => Int = {
    case i ~ ps => (i /: ps)(reduce) 
  }

  def reduce(x: Int, r: String ~ Int) = (r: @unchecked) match {
    case "+" ~ y => x + y
    case "-" ~ y => x - y
    case "*" ~ y => x * y
    case "/" ~ y => x / y
  }

  def expr  : Parser[Int] = term ~ rep ("+" ~ term | "-" ~ term) ^^ reduceList
  def term  : Parser[Int] = factor ~ rep ("*" ~ factor | "/" ~ factor) ^^ reduceList
  def factor: Parser[Int] = "(" ~> expr <~ ")" | numericLit ^^ (_.toInt)

  def main(args: Array[String]) {
    val s = scala.io.Source.fromFile(args(0)).mkString
    val tokens = new lexical.Scanner(s)
    println(s)
    println(phrase(expr)(tokens))
  }
}

【问题讨论】:

  • 我无法重现崩溃。嵌套括号多少层让程序抛出异常?
  • 我也试过了,并且(使用默认的 jvm 堆栈大小)在遇到堆栈溢出之前必须上升到 3500 级(= 括号对数)!这为现实世界的表达留下了相当大的空间......@buerger:我很想知道你是否在更合理的水平上发生了堆栈溢出,否则哪个用例需要那么多嵌套。
  • 改进解析器库的一种方法是使其使用显式堆栈。任何级别的嵌套都是合理的。但没有任何修改库的假设方式是合理的。
  • 理论上可以,可以解析的表达式的复杂度应该没有限制。在实践中,计算中的任何事物都受到限制,无论是时间(有时计算时间太长而无法实际使用)或内存(这绝对是有界的)。需要明确的是,如果您尝试使其编译表达式((((((((... 1 + 1 ...))))))))),嵌套级别为3500,则scala编译器本身将发生堆栈溢出。试试吧。
  • 并且使用显式堆栈肯定会极大地帮助事情,但在某一时刻,您的堆栈将再次占用整个内存,您会碰壁。我知道我可能看起来很迂腐,但我想说的是,你一定需要限制。所以真正唯一真正的问题是:3500 的水平是不可接受的限制吗?

标签: parsing scala recursion stack-overflow


【解决方案1】:

我不确定您将如何使用 scala 解析器组合器来处理它。我的第一个想法是蹦床[1] - 但是快速谷歌搜索似乎说默认库不支持这个。因此,我认为解决这个问题的主要方法是使用-Xss,这不太理想。

不过https://github.com/djspiewak/gll-combinators 支持蹦床,而且好像和标准库有类似的API。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-17
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多