2011-06-14 64 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