我正在尝试复制简单if语句的结构:
if (paren) { block } [else ({ block } | rec if (paren)) ]
对于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
建议?
答案 0 :(得分: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
而不是opt
。 opt
表示else
部分是可选的(如果不存在,则获得None
)。 attempt
完全不同:
解析器
attempt p
适用 解析器p
。如果更改后p
失败 解析器状态或致命的 错误,attempt p
将回溯到 原始解析器状态并报告a 非致命错误。
当attempt
中的解析器失败时,仍然存在错误,但输入未被消耗(当与<|>
或choice
运算符结合使用时,它很有用。)