2010-03-05 46 views
7

我正在嘗試解析器組合器,我經常遇到似乎無限遞歸的情況。這是我遇到的第一個問題:解析器組合器沒有終止 - 如何記錄發生了什麼?

import util.parsing.combinator.Parsers 
import util.parsing.input.CharSequenceReader 

class CombinatorParserTest extends Parsers { 

    type Elem = Char 

    def notComma = elem("not comma", _ != ',') 

    def notEndLine = elem("not end line", x => x != '\r' && x != '\n') 

    def text = rep(notComma | notEndLine) 

} 

object CombinatorParserTest { 

    def main(args:Array[String]): Unit = { 
    val p = new CombinatorParserTest() 
    val r = p.text(new CharSequenceReader(",")) 
    // does not get here 
    println(r) 
    } 

} 

如何打印發生了什麼?爲什麼這不完成?

回答

4

記錄嘗試解析notCommanotEndLine表明它是文件結尾(在log(...)(「mesg」)輸出中顯示爲CTRL-Z),該文件正在被重複分析。以下是我修改解析器用於此目的:

def text = rep(log(notComma)("notComma") | log(notEndLine)("notEndLine")) 

我不能完全肯定發生了什麼事(我想在你的語法許多變化),但我認爲這是這樣的:在EOF是不是一個真正的字符人爲地引入到輸入流中,而是在輸入結束時的一種永久狀態。因此,這個永不消耗的EOF僞字符被重複解析爲「不是逗號或不是行尾」。

+0

我認爲EOF是人爲引進,但你說得對,這是在似乎重複設置請求時反覆解析當輸入已經在序列的末尾時還有一個額外的字符。 – huynhjl 2010-03-06 18:08:55

2

好的,我想我已經想通了。 `CharSequenceReader返回'\ 032'作爲輸入結束的標記。所以,如果我修改我的輸入是這樣,它的工作原理:爲CharSequenceReaderhere

import util.parsing.combinator.Parsers 
import util.parsing.input.CharSequenceReader 

class CombinatorParserTest extends Parsers { 

    type Elem = Char 

    import CharSequenceReader.EofCh 

    def notComma = elem("not comma", x => x != ',' && x!=EofCh) 

    def notEndLine = elem("not end line", x => x != '\r' && x != '\n' && x!=EofCh) 

    //def text = rep(notComma | notEndLine) 
    def text = rep(log(notComma)("notComma") | log(notEndLine)("notEndLine")) 

} 

object CombinatorParserTest { 

    def main(args:Array[String]): Unit = { 
    val p = new CombinatorParserTest() 
    val r = p.text(new CharSequenceReader(",")) 
    println(r) 
    } 

} 

查看源代碼。如果scaladoc提到它,它會爲我節省很多時間。

+1

找出應該提及的地方,然後打開文檔憑單。如果你可以用修改過的scaladoc提供補丁,那就更好了。 – 2010-03-06 02:44:47

+0

已提交https://lampsvn.epfl.ch/trac/scala/ticket/3147。有多個文件使用'EofCh',所以我不確定最好的地方在哪裏。 – huynhjl 2010-03-06 04:34:52

0

我發現日誌功能是非常尷尬的類型。喜歡爲什麼我必須做log(parser)("string")?爲什麼不能像parser.log("string")那樣簡單?不管怎麼說,要克服的是,我做了這個:

trait Logging { self: Parsers => 

    // Used to turn logging on or off 
    val debug: Boolean 

    // Much easier than having to wrap a parser with a log function and type a message 
    // i.e. log(someParser)("Message") vs someParser.log("Message") 
    implicit class Logged[+A](parser: Parser[A]) { 
     def log(msg: String): Parser[A] = 
      if (debug) self.log(parser)(msg) else parser 
    } 
} 
在解析器

現在,你可以混合在這個特質,像這樣:

import scala.util.parsing.combinator.Parsers 
import scala.util.parsing.input.CharSequenceReader 


object CombinatorParserTest extends App with Parsers with Logging { 

    type Elem = Char 

    override val debug: Boolean = true 

    def notComma: Parser[Char] = elem("not comma", _ != ',') 
    def notEndLine: Parser[Char] = elem("not end line", x => x != '\r' && x != '\n') 
    def text: Parser[List[Char]] = rep(notComma.log("notComma") | notEndLine.log("notEndLine")) 

    val r = text(new CharSequenceReader(",")) 

    println(r) 
} 

您也可以覆蓋debug場關閉日誌如果需要的話。

運行,這也顯示了第二語法分析器分析正確的逗號:

trying notComma at [email protected] 
notComma --> [1.1] failure: not comma expected 

, 
^ 
trying notEndLine at [email protected] 
notEndLine --> [1.2] parsed: , 
trying notComma at [email protected] 
notComma --> [1.2] failure: end of input 

, 
^ 
trying notEndLine at [email protected] 
notEndLine --> [1.2] failure: end of input 

, 
^ 
The result is List(,) 

Process finished with exit code 0 
相關問題