sch*_*cht 5 performance parsing scala parser-combinators
我在scala中为我的解析器编写了一个新的组合子.
它是^^组合子的变体,它传递位置信息.但访问输入元素的位置信息确实是性价比.
在我的情况下,解析一个大的例子需要大约3秒没有位置信息,它需要超过30秒.
我编写了一个可运行的示例,其中运行时在访问位置时大约多50%.
这是为什么?我怎样才能获得更好的运行时间?
例:
import scala.util.parsing.combinator.RegexParsers
import scala.util.parsing.combinator.Parsers
import scala.util.matching.Regex
import scala.language.implicitConversions
object FooParser extends RegexParsers with Parsers {
var withPosInfo = false
def b: Parser[String] = regexB("""[a-z]+""".r) ^^@ { case (b, x) => b + " ::" + x.toString }
def regexB(p: Regex): BParser[String] = new BParser(regex(p))
class BParser[T](p: Parser[T]) {
def ^^@[U](f: ((Int, Int), T) => U): Parser[U] = Parser { in =>
val source = in.source
val offset = in.offset
val start = handleWhiteSpace(source, offset)
val inwo = in.drop(start - offset)
p(inwo) match {
case Success(t, in1) =>
{
var a = 3
var b = 4
if(withPosInfo)
{ // takes a lot of time
a = inwo.pos.line
b = inwo.pos.column
}
Success(f((a, b), t), in1)
}
case ns: NoSuccess => ns
}
}
}
def main(args: Array[String]) = {
val r = "foo"*50000000
var now = System.nanoTime
parseAll(b, r)
var us = (System.nanoTime - now) / 1000
println("without: %d us".format(us))
withPosInfo = true
now = System.nanoTime
parseAll(b, r)
us = (System.nanoTime - now) / 1000
println("with : %d us".format(us))
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
没有:2952496我们
用:4591070我们
不幸的是,我认为您不能使用相同的方法。问题是行号最终实现为每次创建时scala.util.parsing.input.OffsetPosition
都会构建每个换行符的列表。因此,如果它最终以字符串输入结束,它将在每次调用时解析整个内容(在您的示例中两次)。有关更多详细信息,请参阅CharSequenceReader和OffsetPosition的代码。pos
您可以做一件事来加快速度:
val ip = inwo.pos
a = ip.line
b = ip.column
Run Code Online (Sandbox Code Playgroud)
至少避免创建pos
两次。但这仍然给你留下了很多多余的工作。恐怕要真正解决这个问题,您必须像OffsetPosition
自己一样构建索引,只需一次,然后继续引用它。
您还可以提交错误报告/提出增强请求。这不是实现该功能的好方法。