2013-07-03 87 views
6

我想使用Scala解析器組合器來實現一些定義語言的解析器。但是,編譯該語言的軟件並未實現所有語言的功能,所以如果使用這些功能,我想失敗。我試圖建立下面一個小例子:Scala解析器組合器中的錯誤和失敗

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

即解析器的「你好」 +一些識別成功,但失敗如果標識符爲「世界」。我發現Parsers類中存在fail()和err()解析器,但我無法弄清楚如何使用它們,因爲它們返回Parser [Nothing]而不是String。這個文檔似乎沒有涵蓋這個用例...

回答

7

在這種情況下,你想要err,而不是failure,因爲如果第一個解析器在析取失敗,你會轉移到第二個,這不是你想。

的另一個問題是,^^map等價,但你要flatMap,因爲err("whatever")Parser[Nothing],而不是一個Nothing。你可以使用上ParserflatMap方法,但是在這種情況下它更習慣使用(完全等同)>>操作:

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" } 
} 

兩種方法都應該做你想做的事。

+0

這正是我一直在尋找。是否>>,〜>(和<〜)操作符記錄在某處(Scaladoc之外,這對我來說不夠詳細)? – scand1sk

+0

@ scand1sk:參見['Parsers#Parser'](http://www.scala-lang.org/api/current/index.html#scala.util.parsing.combinator.Parsers$Parser)類來獲取文檔。 – senia

+1

我猜''你好「〜」世界「>>'是拼寫錯誤,應該有''hello'〜>'world >> >>'使用'$ x'。 – senia

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." 
) 
} 
+0

不幸的是,這個解決方案在我的全局解析器項目中會太麻煩...... – scand1sk

+0

@ scand1sk:'>>'是您的案例中最好的解決方案。但是'^?'允許你使用這樣的附加方法:'case _〜id if isValidId(id)=>'。 – senia

相關問題