Why is my FParsec parser failing to recognize a block comment?

54 Views Asked by At

I'm trying to parse C style comments using FParsec. Not sure why this is failing:

My parser code:

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

Test Harness:

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
()

Error messager. It is the same for both charsTillString and manyCharsTill

Error in Ln: 6 Col: 4
   
   ^
Note: The error occurred at the end of the input stream.
Could not find the string '*/'.

Comment and IgnoreU are both a discrimated type of string

1

There are 1 best solutions below

0
Brian Berns On BEST ANSWER

The problem is that the combinators in your comment parser don't have the precedence/associativity that you want. You can fix this by grouping with parens:

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

I find that choice is often easier to read than <|> for complex parsers:

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

Related Questions in F#