为什么我的 FParsec 解析器无法识别块注释?

Jer*_*rry 1 f# fparsec

我正在尝试使用 FParsec 解析 C 风格注释。不知道为什么会失败:

我的解析器代码:

let openComment : Parser<_,unit>  = pstring "/*"
let closeComment : Parser<_,unit> = pstring "*/"
let comment = pstring "//" >>. restOfLine true
                <|> openComment >>. (charsTillString "*/" true System.Int32.MaxValue) |>> Comment
                //<|> openComment >>. manyCharsTill anyChar closeComment |>> Comment
let spaceComments = many ((spaces1 |>> IgnoreU) <|> comment)
let str s  = spaceComments >>. pstring s .>> spaceComments
Run Code Online (Sandbox Code Playgroud)

测试线束:

let testStr = @"
// test comment
/* a block comment
   */
   x  // another comment
   "
match run (str "x") testStr with
| Success(result, _, _)   -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> assert false
()

Run Code Online (Sandbox Code Playgroud)

错误消息发送器。charsTillString 和 ManyCharsTill 都是相同的

Error in Ln: 6 Col: 4
   
   ^
Note: The error occurred at the end of the input stream.
Could not find the string '*/'.
Run Code Online (Sandbox Code Playgroud)

Comment 和 IgnoreU 都是可区分的字符串类型

bri*_*rns 5

问题是comment解析器中的组合器没有您想要的优先级/关联性。您可以通过用括号分组来解决此问题:

let comment = (pstring "//" >>. restOfLine true)
                <|> (openComment >>. (charsTillString "*/" true System.Int32.MaxValue)) |>> Comment
Run Code Online (Sandbox Code Playgroud)

我发现这通常比复杂的解析器choice更容易阅读:<|>

let comment =
    choice [
        pstring "//" >>. restOfLine true
        openComment >>. (charsTillString "*/" true System.Int32.MaxValue)
    ] |>> Comment
Run Code Online (Sandbox Code Playgroud)