2010-11-23 13 views
1

私は単純なtodoリスト言語(TaskPaperからのデータ)を単純なパーサーコンビネータの例として解析するためにfparsecを使用しようとしています。しかし、私は困惑することができないバグに遭遇しました。私はパーサーコンビネータには新しく、FParsecはParsecを知っている私に頼っているようですが、私はparsecのドキュメントを解読できません。 「:」「 - 」 FParsecとデリミタベースの構文

  • どれ
  • タスクで起動しているタスク紙言語の

    ルールは

    • プロジェクトは、で終わる(私は今の@tagsを無視しています)簡単です他のテキスト行は、プロジェクトまたはタスクのプレーンテキストです。

    したがって、 "Project 1:\ nSome note \ nProject 2:"という文字列は[ProjectName( "Project 1")としてparseFileから返されます。 NoteText( "Some note"); ProjectName( "Projec 「ProjectName」(「Project 1」)、ProjectName(「Some note \ nProject 2」)]

    以下は私のパーサーコードです。

    open FParsec.Primitives 
    open FParsec.CharParsers 
    type ProjectAst = ProjectName of string 
            | TaskText of string 
            | NoteText of string 
    
    let asString (x:char list) :string = 
        x 
        |> List.map (fun y -> y.ToString()) 
        |> String.concat "" 
    let makeNote x = NoteText(asString x) 
    let parseProject = 
        parse { let! s = many (noneOf ":\n\r\c") 
          do! skipChar ':' 
          return ProjectName(asString s) } 
    let parseTask = 
        parse { do! skipChar '-' 
          let! s = many (noneOf "\n\r\c") 
          return TaskText(asString s) } 
    let parseNote = many (noneOf "\n\r\c") |>> makeNote 
    
    let parseLine = parseTask <|> (attempt parseProject) <|> parseNote 
    let parseFile = sepBy parseLine (many1 whitespace) 
    

    編集構文はHogbayソフトウェアのTaskPaperアプリケーションから構文のTaskPaper website いくつかの例をとっている

     
        Project 1: 
        Description of Project One 
        -task for project 1 
        -another task for project 1 
        details for another task 
        -final task 
    
        Go to store: 
        -buy eggs 
        -buy milk 
    
  • +0

    私はコードを実行し、 '[NoteText" Proje "]'を得ました –

    +0

    この形式の代表的なサンプルを投稿できますか? –

    +0

    このコードは大丈夫です。 '\ n'をどこでも(入力を含めて)' \ n 'に置き換え、 'whiteSpace'を' skipChar' * ''で置き換えるのは興味深いでしょう。これは改行問題のようなにおいがします。 – Brian

    答えて

    3
    私はFParsecでスーパー流暢ないんだけど

    が、この1作品:

    let newline = pchar '\n' 
    let notNewLine = noneOf "\n" 
    let allTillEOL = manyChars notNewLine 
    
    let parseProject = 
        let r = manyCharsTill (noneOf ":\n") (pchar ':') 
        r |>> ProjectName 
    
    let parseTask = 
        let r = skipChar '-' >>. allTillEOL 
        r |>> TaskText 
    
    let parseNote = allTillEOL |>> NoteText 
    
    let parseLine = parseTask <|> attempt parseProject <|> parseNote 
    let parseFile = sepBy parseLine newline 
    
    let a = run parseFile "Project 1:\nSome note\nProject 2:\n-One Task" 
    match a with 
    | Success (a,b,c) -> printfn "%A" a 
    | Failure (a,b,c) -> printfn "failed: %s" a 
    

    プリントアウト:

    [ProjectName "Project 1"; NoteText "Some note"; ProjectName "Project 2"; TaskText "One Task"] 
    

    他の例と比較してテストします。

    私はFParsecを数回使用しましたが、私はモナディックスタイルよりもコンビネータスタイルを好みました。

    +0

    ご協力ありがとうございます。私はparseFileを 'sebBy parseLine(many1(newline <|>空白))'に変更しました。モナド対コンビネータのスタイルに関しては、関数コンビネータはまだ私を恐れています。私はそれを乗り越えようとしていますが、モナド構文は安全で快適な命令的コーディングのように見えます。また、私はあなたの例から新しいF#構文のトリックか2つを選んだと思います! – Ball