使用scala解析器组合解析基于缩进的语言

Rob*_*lan 7 parsing scala indentation parser-combinators

有没有一种方便的方法来使用Scala的解析器组合器来解析缩进很重要的语言?(例如Python)

Kim*_*bel 5

假设我们有一个非常简单的语言,这是一个有效的程序

block
  inside
  the
  block
Run Code Online (Sandbox Code Playgroud)

并且我们想要将其解析为List[String]块中的每一行作为一个String.

我们首先定义一个方法,该方法采用最小缩进级别,并为具有该缩进级别的行返回解析器.

def line(minIndent:Int):Parser[String] = 
  repN(minIndent + 1,"\\s".r) ~ ".*".r ^^ {case s ~ r => s.mkString + r}
Run Code Online (Sandbox Code Playgroud)

然后我们通过在行之间用适当的分隔符重复行解析器来定义具有最小缩进级别的块.

def lines(minIndent:Int):Parser[List[String]] =
  rep1sep(line(minIndent), "[\n\r]|(\n\r)".r)
Run Code Online (Sandbox Code Playgroud)

现在我们可以为我们的小语言定义一个解析器,如下所示:

val block:Parser[List[String]] =
  (("\\s*".r <~ "block\\n".r) ^^ { _.size }) >> lines
Run Code Online (Sandbox Code Playgroud)

它首先确定当前缩进级别,然后将其作为最小值传递给行解析器.我们来测试一下:

val s =
"""block
    inside
    the
    block
outside
the
block"""

println(block(new CharSequenceReader(s)))
Run Code Online (Sandbox Code Playgroud)

我们得到了

[4.10] parsed: List(    inside,     the,     block)
Run Code Online (Sandbox Code Playgroud)

要编译所有这些,您需要这些导入

import scala.util.parsing.combinator.RegexParsers
import scala.util.parsing.input.CharSequenceReader
Run Code Online (Sandbox Code Playgroud)

而且你需要将所有东西放入一个RegexParsers像这样延伸的对象中

object MyParsers extends RegexParsers {
  override def skipWhitespace = false
  ....
Run Code Online (Sandbox Code Playgroud)