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

huangapple go评论50阅读模式
英文:

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

问题

我正在尝试使用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

测试代码:

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

错误信息。无论是charsTillString还是manyCharsTill,都是相同的错误信息:

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

Comment和IgnoreU都是字符串的枚举类型。

英文:

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

My parser code:

let openComment : Parser&lt;_,unit&gt;  = pstring &quot;/*&quot;
let closeComment : Parser&lt;_,unit&gt; = pstring &quot;*/&quot;
let comment = pstring &quot;//&quot; &gt;&gt;. restOfLine true
                &lt;|&gt; openComment &gt;&gt;. (charsTillString &quot;*/&quot; true System.Int32.MaxValue) |&gt;&gt; Comment
                //&lt;|&gt; openComment &gt;&gt;. manyCharsTill anyChar closeComment |&gt;&gt; Comment
let spaceComments = many ((spaces1 |&gt;&gt; IgnoreU) &lt;|&gt; comment)
let str s  = spaceComments &gt;&gt;. pstring s .&gt;&gt; spaceComments

Test Harness:

let testStr = @&quot;
// test comment
/* a block comment
   */
   x  // another comment
   &quot;
match run (str &quot;x&quot;) testStr with
| Success(result, _, _)   -&gt; printfn &quot;Success: %A&quot; result
| Failure(errorMsg, _, _) -&gt; 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 &#39;*/&#39;.

Comment and IgnoreU are both a discrimated type of string

答案1

得分: 5

问题在于您的 comment 解析器中的组合子没有您想要的优先级/结合性。您可以通过使用括号进行分组来修复这个问题:

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

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

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

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 &quot;//&quot; &gt;&gt;. restOfLine true)
                &lt;|&gt; (openComment &gt;&gt;. (charsTillString &quot;*/&quot; true System.Int32.MaxValue)) |&gt;&gt; Comment

I find that choice is often easier to read than &lt;|&gt; for complex parsers:

let comment =
    choice [
        pstring &quot;//&quot; &gt;&gt;. restOfLine true
        openComment &gt;&gt;. (charsTillString &quot;*/&quot; true System.Int32.MaxValue)
    ] |&gt;&gt; Comment

huangapple
  • 本文由 发表于 2023年6月1日 23:59:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76383755.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定