我想解析F#類型的語法。我開始寫一個[F]秒差距語法,遇到了問題,所以我簡化the grammar到這一點:Parsec:回溯不工作
type ::= identifier | type -> type
identifier ::= [A-Za-z0-9.`]+
運行與FParsec問題之後,我切換到秒差距,因爲我有一個full chapter of a book dedicated to explaining it。我給這家文法代碼是
typeP = choice [identP, arrowP]
identP = do
id <- many1 (digit <|> letter <|> char '.' <|> char '`')
-- more complicated code here later
return id
arrowP = do
domain <- typeP
string "->"
range <- typeP
return $ "("++domain++" -> "++range++")"
run = parse (do t <- typeP
eof
return t) "F# type syntax"
的問題是,秒差距默認不走回頭路,所以
> run "int"
Right "int"
-- works!
> run "int->int"
Left "F# type syntax"
unexpected "-"
expecting digit, letter, ".", "`" or end of input
-- doesn't work!
我想的第一件事就是重新安排typeP:
typeP = choice [arrowP, identP]
但是這個堆棧溢出了,因爲語法是左遞歸的 - typeP永遠不會嘗試identP
,因爲它一直試圖反覆嘗試arrowP
。接下來,我在不同的地方嘗試try
,例如:
typeP = choice [try identP, arrowP]
但沒有我這樣做似乎改變(1)棧溢出或(2)不承認的基本行爲 - 一個標識符下面的「>」。
對於成功編寫Parsec語法的人來說,我的錯誤可能是很明顯的。有人可以指出嗎?
很好的解釋。正如你注意到的那樣,問題的根源在於你需要打破箭頭P可以下降到typeP的循環,而typeP本身可以下降到typeP。我認爲你的'parens'例子特別具有啓發性。 – kvb 2010-03-08 20:41:07
因此,Parsec語法與LR(1)語法具有基本相同的非組成問題,因爲您必須規劃整個語法,以便每條規則的左邊最終重寫爲明確的文字。哦,我想我應該知道比假設帕塞克是魔術更好。 – 2010-03-09 15:46:22