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

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

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

问题

我正在尝试使用FParsec解析C样式的注释。不确定为什么会失败:

我的解析器代码:

  1. let openComment : Parser<_,unit> = pstring "/*"
  2. let closeComment : Parser<_,unit> = pstring "*/"
  3. let comment = pstring "//" >>. restOfLine true
  4. <|> openComment >>. (charsTillString "*/" true System.Int32.MaxValue) >> Comment
  5. // <|> openComment >>. manyCharsTill anyChar closeComment >> Comment
  6. let spaceComments = many ((spaces1 >> IgnoreU) <|> comment)
  7. let str s = spaceComments >>. pstring s >> spaceComments

测试代码:

  1. let testStr = @"
  2. // test comment
  3. /* a block comment
  4. */
  5. x // another comment
  6. "
  7. match run (str "x") testStr with
  8. | Success(result, _, _) -> printfn "Success: %A" result
  9. | Failure(errorMsg, _, _) -> assert false
  10. ()

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

  1. Error in Ln: 6 Col: 4
  2. ^
  3. Note: The error occurred at the end of the input stream.
  4. 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:

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

Test Harness:

  1. let testStr = @&quot;
  2. // test comment
  3. /* a block comment
  4. */
  5. x // another comment
  6. &quot;
  7. match run (str &quot;x&quot;) testStr with
  8. | Success(result, _, _) -&gt; printfn &quot;Success: %A&quot; result
  9. | Failure(errorMsg, _, _) -&gt; assert false
  10. ()

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

  1. Error in Ln: 6 Col: 4
  2. ^
  3. Note: The error occurred at the end of the input stream.
  4. Could not find the string &#39;*/&#39;.

Comment and IgnoreU are both a discrimated type of string

答案1

得分: 5

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

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

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

  1. let comment =
  2. choice [
  3. pstring "//" >>. restOfLine true
  4. openComment >>. (charsTillString "*/" true System.Int32.MaxValue)
  5. ] >>. 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:

  1. let comment = (pstring &quot;//&quot; &gt;&gt;. restOfLine true)
  2. &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:

  1. let comment =
  2. choice [
  3. pstring &quot;//&quot; &gt;&gt;. restOfLine true
  4. openComment &gt;&gt;. (charsTillString &quot;*/&quot; true System.Int32.MaxValue)
  5. ] |&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:

确定