4

我正在尝试复制一个简单 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

建议?

4

1 回答 1

5

你看过我的 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将回溯到原始解析器状态并报告非致命错误。

当解析器attempt失败时,仍然有错误,但输入没有被消耗(与<|>orchoice运算符结合使用时很有用)。

于 2011-06-14T18:01:05.417 回答