[英]FParsec - parser sequences
Say I have some text: 说我有一些文字:
a = "foobarbaz"
b = "foobar"
c = "foo"
d = "rubbish"
e = "foobazbar"
and three parsers foo, bar, and baz for the strings 'foo', 'bar' and 'baz' respectively. 和三个解析器foo,bar和baz分别表示字符串“ foo”,“ bar”和“ baz”。
How would I create a parser that would give me the results: 我将如何创建一个解析器,使我得到结果:
a = ["foo", "bar", "baz"]
b = ["foo", "bar"]
c = ["foo"]
d = []
e = ["foo"]
when run against the inputs above? 在上面的输入下运行时? Basically attempt each possibility until failure whilst constructing a list. 构造列表时,基本上尝试各种可能性,直到失败为止。 I could use user state but I would like to avoid if possible. 我可以使用用户状态,但如果可能的话,我想避免使用。 (I would like to keep the individual parsers themselves ignorant of user state) (我想让各个解析器自己不了解用户状态)
the closest I have gotten is something like fooseq below: 我得到的最接近的是下面的fooseq之类的东西:
let foo = pstring "foo"
let bar = pstring "bar"
let baz = pstring "baz"
let foobar = pipe2 foo bar Seq.of2
let foobarbaz = pipe3 foo bar baz Seq.of3
let fooseq = choice (Seq.map attempt [foobarbaz; foobar; foo |>> Seq.of1 ;])
//(the Seq.ofx functions just take arguments and create a sequence of them)
It seems to me there must be a better way of doing this? 在我看来,必须有更好的方法来做到这一点?
FParsec has no built-in sequence combinator that does exactly what you're looking for, but you could implement one yourself like in the following example: FParsec没有内置的序列组合器可以完全满足您的需求,但是您可以像下面的示例一样自己实现:
let mySeq (parsers: seq<Parser<'t,'u>>) : Parser<'t[],'u> =
let ps = Array.ofSeq parsers
if ps.Length = 0 then preturn [||]
else
fun stream ->
let mutable stateTag = stream.StateTag
let mutable reply = ps.[0] stream
let mutable error = reply.Error
let mutable myReply = Reply()
if reply.Status <> Ok then myReply.Result <- [||]
else
// create array to hold results
let mutable xs = Array.zeroCreate ps.Length
xs.[0] <- reply.Result
let mutable i = 1
while i < ps.Length do
stateTag <- stream.StateTag
reply <- ps.[i] stream
error <- if stateTag <> stream.StateTag then reply.Error
else mergeErrors error reply.Error
if reply.Status = Ok then
xs.[i] <- reply.Result
i <- i + 1
else // truncate array and break loop
xs <- Array.sub xs 0 i
i <- ps.Length
myReply.Result <- xs
myReply.Status <- if reply.Status = Error && stateTag = stream.StateTag
then Ok
else reply.Status
myReply.Error <- error
myReply
With the mySeq
combinator, you can express your fooSeq
parser as 使用mySeq
组合器,您可以将fooSeq
解析器表示为
let fooSeq = mySeq [foo; bar; baz]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.