6

我想使用 Scala Parser Combinators 为某些定义的语言实现解析器。但是,编译该语言的软件并没有实现该语言的所有功能,所以如果使用这些功能我会失败。我试图在下面伪造一个小例子:

object TestFail extends JavaTokenParsers {
  def test: Parser[String] =
    "hello" ~ "world" ^^ { case _ => ??? } |
    "hello" ~ ident ^^ { case "hello" ~ id => s"hi, $id" }
}

即,解析器在“hello”+某个标识符上成功,但如果标识符是“world”则失败。我看到 Parsers 类中存在 fail() 和 err() 解析器,但我不知道如何使用它们,因为它们返回 Parser[Nothing] 而不是 String。文档似乎没有涵盖这个用例……</p>

4

2 回答 2

7

在这种情况下,您想要err,而不是failure,因为如果析取中的第一个解析器失败,您将继续执行第二个解析器,这不是您想要的。

另一个问题是,^^它相当于map,但你想要flatMap,因为err("whatever")是 a Parser[Nothing],而不是 a Nothing。您可以使用flatMapon 方法Parser,但在这种情况下,使用(完全等效的)>>运算符更为惯用:

object TestFail extends JavaTokenParsers {
  def test: Parser[String] =
    "hello" ~> "world" >> (x => err(s"Can't say hello to the $x!")) |
    "hello" ~ ident ^^ { case "hello" ~ id => s"hi, $id" }
}

或者,更简单一点:

object TestFail extends JavaTokenParsers {
  def test: Parser[String] =
    "hello" ~ "world" ~> err(s"Can't say hello to the world!") |
    "hello" ~ ident ^^ { case "hello" ~ id => s"hi, $id" }
}

任何一种方法都应该做你想做的。

于 2013-07-03T12:53:29.953 回答
3

你可以使用^?方法:

object TestFail extends JavaTokenParsers {
  def test: Parser[String] =
    "hello" ~> ident ^? (
      { case id if id != "world" => s"hi, $id" },
      s => s"Should not use '$s' here."
  )
}
于 2013-07-03T12:54:33.853 回答