如何在FParsec中添加解析后的数字必须满足的条件? [英] How to add a condition that a parsed number must satisfy in FParsec?

查看:63
本文介绍了如何在FParsec中添加解析后的数字必须满足的条件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to parse an int32 with FParsec but have an additional restriction that the number must be less than some maximum value. Is their a way to perform this without writing my own custom parser (as below) and/or is my custom parser (below) the appropriate way of achieving the requirements.

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

I ask because most of the built-in library functions seem to revolve around a char satisfying certain predicates and not any other type.

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解决方案的方法:

UPDATE

Below is an attempt at a more fitting FParsec solution based on the direction given in the comment below:

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

这是正确的方法吗?

推荐答案

您进行了出色的研究,几乎回答了自己的问题.

You've done an excellent research and almost answered your own question.

通常,有两种方法:

  1. 无条件解析出int并让其他代码检查其有效性;
  2. 使用绑定到解析器的保护规则.在这种情况下,(>>=)是正确的工具;
  1. Unconditionally parse out an int and let the further code to check it for validity;
  2. Use a guard rule bound to the parser. In this case (>>=) is the right tool;

为了做出一个好的选择,请问自己:未通过的整数是否必须通过触发另一个解析器来给另一个机会"?

In order to make a good choice, ask yourself whether an integer that failed to pass the guard rule has to "give another chance" by triggering another parser?

这就是我的意思.通常,在现实生活中的项目中,解析器被组合在某些链中.如果一个解析器失败,则尝试下一个.例如,在此问题中,某些编程语言已被解析,因此它需要类似以下内容:

Here's what I mean. Usually, in real-life projects, parsers are combined in some chains. If one parser fails, the following one is attempted. For example, in this question, some programming language is parsed, so it needs something like:

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

理论上,您的DSL可能需要将小整数值"与另一种类型区分开:

Theoretically, your DSL may need to differentiate a "small int value" from another type:

/// 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将返回:

Built this way, pCombined will return:

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

我们看到,保护规则会影响解析器的应用方式,因此保护规则必须位于解析过程之内.

As we see, the guard rule impacts how the parsers are applied, so the guard rule has to be within the parsing process.

但是,如果您不需要这种复杂的操作(例如,无条件地解析int ),则您的第一个代码段就可以了.

If, however, you don't need such complication (e.g., an int is parsed unconditionally), your first snippet is just fine.

这篇关于如何在FParsec中添加解析后的数字必须满足的条件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆