2013-07-21 3 views
2

내가 텍스트를 말해봐.FParsec 파서 시퀀스

내가 나에게 결과를 줄 것이다 파서 만들 것입니다 방법 :

a = ["foo", "bar", "baz"] 
b = ["foo", "bar"] 
c = ["foo"] 
d = [] 
e = ["foo"] 

위의 입력에 대해 실행? 기본적으로 실패 할 때까지리스트를 작성하는 동안 각 가능성을 시도하십시오. 사용자 상태를 사용할 수는 있지만 가능하면 피하고 싶습니다.

그것은 나에게 보인다
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)  

이가 있어야이 일을 더 나은 방법 : (I 사용자의 상태를 스스로 무지 개별 파서를 유지하고 싶은)

내가 찍었을 가장 가까운 아래 fooseq 같은입니다 ?

답변

5

FParsec은 당신이 찾고있는 정확하게 수행에는 내장 시퀀스 콤비가 없습니다,하지만 당신은 다음 예에서와 같이 하나 직접 구현할 수 다음 mySeq 콤비로

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 

, 당신이 표현할 수 있습니다 fooSeq 파서를

let fooSeq = mySeq [foo; bar; baz]