【问题标题】:How to skip whitespace but use it as a token delimeter in a parser combinator如何跳过空格但将其用作解析器组合器中的标记分隔符
【发布时间】:2013-12-27 00:21:22
【问题描述】:

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

我正在扩展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+) <~ ")"

【问题讨论】:

  • IIRC,跳过空白仅在每个标记的开头完成,直到找到第一个非空白字符。这与您所说的情况不一致,您能否提供示例代码和测试用例?
  • @DanielC.Sobral 添加了一个小例子来说明它正在发生。

标签: scala parser-combinators


【解决方案1】:

在每个产生式规则之前都会跳过空格。所以,在这个 sn-p 中:

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

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

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

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

  // ...

【讨论】:

  • 不确定我得到了空字符串部分。那么是因为我有一个单独的 anyChar 规则吗?所以在此之前,空格将再次被跳过,但 anyChar 仍然需要在更高级别的name 解析器中组合?那么小的anyChars 正在一个一个地吞噬更多的代币?
  • @jbx 是的。空字符串是一个单独的问题,与手头的问题并不真正相关。在每个解析器之前,不仅anyChar是解析器,甚至letterdigit都被隐式转换为解析器,空格被跳过。
  • 您不能将语义操作放在正则表达式上。正则表达式的结果会生成一个普通的非结构化字符串。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-11
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多