scala组合器解析器保持原始输入

时间:2012-01-26 15:50:05

标签: scala parser-combinators

我想从另一个解析器编写一个解析器,将消耗的输入作为ast构造的参数。

说我有

def ingredient = amount ~ nameOfIngredient ^^ {
  case amount ~ name => Ingredient(name, amount)
}

我正在寻找的方法是让另一个解析器构造一个元素:

case class RecipeRow(orginalText: String, ingredient: Ingredient)

所以我正在寻找一种方法来检索合成中解析器的原始消耗输入。也许是这样的:

def recipeRow = ingredient withConsumedInput ^^ {
  case (amount ~ name, consumed) => RecipeRow(consumed, Ingredient(name, amount))
}

我猜这种情况下的签名是:

def withConsumedInput [U](p: => Parser[U]): Parser[(U, String)]

还有另一种简单的方法可以获得我想要的东西吗?我需要写那个东西吗?感觉它可能是一种更好的方式......

1 个答案:

答案 0 :(得分:4)

实际上并不容易。

让我们从Parser开始:它能给我们带来什么?好吧,Parser扩展Input => ParseResult,因此我们必须从任何一个中提取信息。

类型InputRegexParsers的别名,scala.util.parsing.input.Reader[Char]。除非它恰好是Reader CharSequence,否则我们可以使用sourceoffset来帮助我们。那就让我们使用它。

现在,ParseResult有许多子类,但我们只对Success感兴趣,next: Input有一个def withConsumedInput [U](p: => Parser[U]): Parser[(U, String)] = new Parser[(U, String)] { def apply(in: Input) = p(in) match { case Success(result, next) => val parsedString = in.source.subSequence(in.offset, next.offset).toString Success(result -> parsedString, next) case other: NoSuccess => other } } 字段。使用它,我们可以试试这个:

def withConsumedInput [U](p: => Parser[U]): Parser[(U, String)] = new Parser[(U, String)] {
  def apply(in: Input) = p(in) match {
    case Success(result, next) =>
      val parsedString = in.source.subSequence(handleWhiteSpace(in.source, in.offset), next.offset).toString
      Success(result -> parsedString, next)
    case other: NoSuccess      => other
  }
}

但它会捕获任何跳过的空格。您可以对其进行调整以自动避免:

{{1}}