f# - 解析 if/else/if 语句

标签 f# fparsec

我试图复制一个简单的 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

建议?

最佳答案

你有没有看过我的 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完全不同:

The parser attempt p applies the parser p. If p fails after changing the parser state or with a fatal error, attempt p will backtrack to the original parser state and report a non‐fatal error.



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

关于f# - 解析 if/else/if 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6341288/

相关文章:

f# - 如果 "till"解析器以空格开头,为什么 manyCharsTill 组合器不起作用?

parsing - 如何使用 FParsec 解析字符串值

f# - 由于循环引用,确定如何订购 F# 类型的问题

functional-programming - 在不使用嵌套 map 的情况下为列表列表实现 map 功能

.net - 可区分联合中的函数约束泛型参数的类型

f# - 解析括号表达式

.net - 在F#中使用自定义Marshaller

entity-framework - 将 F# 类型保存到数据库

f# - 如何为 .NET Compact Framework 构建 FParsec?