我正在尝试使用 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
UPDATE
下面是根据下面评论中给出的方向尝试更合适的 FParsec 解决方案:
let pRow2: Parser<int> =
pint32 >>= (fun x -> if x <= 1048576 then (preturn x) else fail "int parsed larger than maxRows")
这是正确的方法吗?
您做了出色的研究,几乎回答了您自己的问题。
一般来说,有两种方法:
-
无条件地解析出一个
int
并让进一步的代码检查其有效性;
- Use a 警卫规则绑定到解析器。在这种情况下
(>>=)
是正确的工具;
为了做出好的选择,问问自己是否有一个整数failed要通过守卫规则必须通过触发“再给一次机会”另一个解析器?
这就是我的意思。通常,在现实项目中,解析器会组合在一些链中。如果一个解析器失败,则会尝试下一个解析器。例如,在这个问题,某些编程语言被解析,所以它需要类似:
let pContent =
pLineComment <|> pOperator <|> pNumeral <|> pKeyword <|> pIdentifier
理论上,您的 DSL 可能需要将“小 int 值”与其他类型区分开来:
/// 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
被解析无条件地),你的第一个片段就很好。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)