如何跳过空格,但在解析器组合器中将其用作标记分隔符

时间:2013-12-27 00:21:23

标签: scala parser-combinators

我正在尝试构建一个小解析器,其中令牌(幸运的是)从不包含空格。空格(空格,制表符和换行符)本质上是令牌分隔符(除了有括号等的情况)。

我正在扩展RegexParsers课程。如果我打开skipWhitespace,当下一个标记与前一个标记的正则表达式匹配时,解析器会贪婪地加入标记。另一方面,如果我关闭skipWhitespace,它会因为空格不属于定义而抱怨。我试图尽可能地匹配BNF,并且假设空格几乎总是分隔符(除了括号或其他在BNF中明确定义分隔符的情况),是否可以避免将空白正则表达式放在所有区域中我的定义?

更新

这是一个小型测试示例,其中令牌连接在一起:

import scala.util.parsing.combinator.RegexParsers

object TestParser extends RegexParsers {
  def test  = "(test" ~> name <~ ")"

  def name : Parser[String] = (letter ~ (anyChar*)) ^^ { case first ~ rest => (first :: rest).mkString}

  def anyChar = letter | digit | "_".r | "-".r
  def letter = """[a-zA-Z]""".r
  def digit = """\d""".r

  def main(args: Array[String]) {

    val s = "(test hello these should not be joined and I should get an error)"

    val res = parseAll(test, s)
    res match {
      case Success(r, n) => println(r)
      case Failure(msg, n) => println(msg)
      case Error(msg, n) => println(msg)
    }

  }

}

在上面的例子中,我只是将字符串连接在一起。 类似的效果是如果我将test更改为以下内容,期望它在测试后给我单独的单词列表,但它将它们连接在一起并且只给我一个带有长字符串的单元素列表,而不是中间空间:

def test  = "(test" ~> (name+) <~ ")"

1 个答案:

答案 0 :(得分:4)

在每个生产规则之前跳过空白区域。所以,在这个片段中:

def name : Parser[String] = (letter ~ (anyChar*)) ^^ { case first ~ rest => (first :: rest).mkString}

它会在每个字母之前跳过空格,更糟糕的是,每个字符串都是好的衡量标准(因为anyChar*可以为空)。

为每个标记使用正则表达式(或纯字符串),而不是每个词法元素。像这样:

object TestParser extends RegexParsers {
  def test  = "(test" ~> name <~ ")"
  def name : Parser[String] = """[a-zA-Z][a-zA-Z0-9_-]*""".r

  // ...