如何在FParsec中添加解析后的数字必须满足的条件?

时间:2015-08-11 10:23:09

标签: f# fparsec

我正在尝试使用FParsec解析int32,但是还有一个限制,即该数字必须小于某个最大值。他们是一种在不编写我自己的自定义解析器(如下所示)和/或我的自定义解析器(如下所示)的情况下执行此操作的方法,是实现这些要求的适当方法。

我问,因为大多数内置库函数似乎都围绕 char 来满足某些谓词,而不是任何其他类型。

let pRow: Parser<int> = 
   let error = messageError ("int parsed larger than maxRows")
   let mutable res = Reply(Error, error)
   fun stream ->
      let reply = pint32 stream
      if reply.Status = Ok && reply.Result <= 1000000 then
         res <- reply
      res

更新

以下是根据以下评论中给出的方向尝试更合适的FParsec解决方案:

let pRow2: Parser<int> = 
   pint32 >>= (fun x -> if x <= 1048576 then (preturn x) else fail "int parsed larger than maxRows")

这是正确的方法吗?

1 个答案:

答案 0 :(得分:6)

你做了很好的研究,几乎回答了你自己的问题。

通常,有两种方法:

  1. 无条件地解析int并让更多代码检查其有效性;
  2. 使用绑定到解析器的保护规则。在这种情况下,(>>=)是正确的工具;
  3. 为了做出一个好的选择,问问自己一个失败传递保护规则的整数是否必须给出另一个机会&#34;通过触发另一个解析器

    这就是我的意思。通常,在现实生活中的项目中,解析器组合在一些链中。如果一个解析器失败,则尝试执行以下操作。例如,在this question中,解析了一些编程语言,因此它需要类似:

    let pContent =
        pLineComment <|> pOperator <|> pNumeral <|> pKeyword <|> pIdentifier
    

    从理论上讲,你的DSL可能需要区分一个小的int值&#34;从另一种类型:

    /// The resulting type, or DSL
    type Output =
        | SmallValue of int
        | LargeValueAndString of int * string
        | Comment of string
    
    let pSmallValue =
        pint32 >>= (fun x -> if x <= 1048576 then (preturn x) else fail "int parsed larger than maxRows")
        |>> SmallValue
    let pLargeValueAndString =
        pint32 .>> ws .>>. (manyTill ws)
        |>> LargeValueAndString
    let pComment =
        manyTill ws
        |>> Comment
    
    let pCombined =
        [ pSmallValue; pLargeValueAndString; pComment]
        |> List.map attempt // each parser is optional
        |> choice // on each iteration, one of the parsers must succeed
        |> many // a loop
    

    以这种方式构建,pCombined将返回:

    • "42 ABC"被解析为[ SmallValue 42 ; Comment "ABC" ]
    • "1234567 ABC"被解析为[ LargeValueAndString(1234567, "ABC") ]

    正如我们所见,保护规则会影响解析器的应用方式,因此保护规则必须在解析过程中。

    但是,如果您不需要此类并发症(例如,int已被无条件解析),那么您的第一个片段就可以了。