2012-01-31 84 views
3

我一直試圖做一個解析器一個非常簡單的語言,它看起來像這樣的Scala解析器組合(幾乎)瑣碎的語法

.*?[^ ]*?\\{ 
.*?\\} 

這將基本上保持吃字符,直到它找到匹配[^ ]*?\\{\\}的東西:塊的開始或結束。我的問題是,如果我想使用Scala的Parser Combinators來做它,我該怎麼做?我目前有:

def expr: Parser[Any] = (block | text)+ 
    def text = ".+?".r 
    def block = "[^ ]*?\\{".r ~ expr ~ "}" 

但這不起作用:

parsed: List(b, l, o, c, k, {, y, o, u, a, r, e, a, c, o, w, t, o, o, b, l, k, A, {, b, u, t, m, a, y, b, e, n, o, t, }, a, n, d, s, o, i, s, h, e, }, h, e, a, r, m, e, m, o, o) 

看來,block解析器不點火,所以text分析器被反覆觸發。但是當我刪除text解析器:

def expr: Parser[Any] = (block)+ 

我得到:

failure: string matching regex `[^ ]*?\{' expected but `y' found 

block{you are a cow too blkA{ but maybe not} and so is he} hear me moo 
    ^

如此明顯的block解析器確實工作,除了沒有當text解析器是存在的。發生了什麼?有沒有一種「適當」的方式來做到這一點,因爲這麼基礎的語法?

編輯:改變了標題,因爲它不是這麼多的不情願了,因爲只是解決問題

編輯:我現在有這樣的:

def expr: Parser[Any] = (block | text)+ 

def text = "[^\\}]".r 

def block = "[^ ]*?\\{".r ~ expr ~ "}" 

這背後的邏輯是,每個字符,它測試它是否是塊的開始。如果不是,則轉到下一個字符。這給我:

parsed: List(((block{~List(y, o, u, a, r, e, a, c, o, w, t, o, o, ((blkA{~List(b, u, t, m, a, y, b, e, n, o, t))~}), a, n, d, s, o, i, s, h, e))~}), h, e, a, r, m, e, m, o, o) 

這是正確的。它一個接一個地解析非塊字符,這可能是一個性能問題(我認爲?)。有沒有辦法一次解析所有這些非塊字符並將它們放在一個大字符串中?

+0

請不要將新問題添加到現有的問題。當然可以加強,但爲新問題提出新問題。因爲你使用了一個非貪婪的星星,所以它是一個接一個的解析。只要放棄非貪婪。 – 2012-02-01 14:20:45

回答

2

的問題是,text被消耗所有閉大括號(})。它是這樣的:

expr -> block -> expr -> text.+ (until all input is consumed) 

在這一點上,它退出expr,並試圖解析},它不存在,失敗,並回落到text第一expr

您可以使用log來看看是怎麼回事,當你分析上。

+0

這引出了一個問題:如何阻止'文本'吃掉我的關閉'}'?就像在正則表達式域中,我可以匹配'。+?[^] *?\\ {'和'。+?\\}'來抓取所有文本,直到下一個開放塊或者關閉塊符號,但是沒有'+?'在PC庫中(據我所知)。有沒有其他方法可以達到同樣的效果? – 2012-02-01 12:32:21

+0

@李哈伊嗯,'.. *?'等同於'。+?',但爲什麼不直接用'[^ ​​{}] +'來代替呢?如果嵌套花括號,則需要將'text'轉換爲遞歸解析器而不是正則表達式 - 正則表達式不處理遞歸。 – 2012-02-01 14:17:59