2011-06-14 67 views
4

我試圖複製一個簡單的if語句的結構:解析的if/else/if語句

if (paren) { block } [else ({ block } | rec if (paren)) ] 

因爲如果(括號)塊,我創建了一個IfBlock AST節點。否則,它會遞歸地填充一個IfElseBlock節點。

我已經嘗試了不少替代結構

let parse_if = 
    suffixparen .>>. suffixblock |>> IfBlock 
    //>>? attempt (str "else" >>. ifParser) |>> IfElseBlock 
    //<|> preturn IfBlock 
    // .>>? attempt (str "else" >>. ifParser) |>> IfElseBlock 
    // suffixparen .>>. suffixblock |>> IfBlock 
    // <|> ifParser |>> IfElseBlock 

let inlineIf = str_ws "if" >>. parse_if 
do ifParserR := inlineIf 

建議?

回答

4

你看過我的GLSL解析器(它是類C語言)嗎? http://laurent.le-brun.eu/fsharp/glsl_parse.fs

從代碼示例,這裏是爲if聲明的相關部分:

let statement, stmtRef = createParserForwardedToRef() 

let ifStatement = 
    pipe3 (keyword "if" >>. parenExp) statement (opt (keyword "else" >>. statement)) 
     (fun cond stmt1 stmt2 -> Ast.If(cond, stmt1, stmt2)) 

stmtRef := choice [ 
    simpleStatement 
    block 
    ifStatement 
    forLoop 
    //... 
    ] 

我覺得你的問題是,你正在使用attempt代替optopt表示else部分是可選的(如果它不在那裏,則得到None)。 attempt是完全不同的:

解析器attempt p應用 解析器p。如果p在更改 解析器狀態或致命 錯誤後失敗,attempt p將回溯到 原始解析器狀態,並報告非致命錯誤 。

attempt解析器失敗,仍有一個錯誤,但該輸入沒有被消耗(當與<|>choice運算符組合是非常有用)。

+0

感謝Laurent。對於記錄,我也試圖結合嘗試和<|>%無與無功。 – hammett 2011-06-14 18:26:37