1

単純なパーサー コンビネーターの例として、fparsec を使用して単純な todo リスト言語 (実際には TaskPaper のデータ) を解析しようとしています。しかし、私はパズルを解くことができないように見えるバグに遭遇しました。私はパーサー コンビネータを初めて使用し、FParsec は私が Parsec を知っていることに依存しているようですが、パーセックのドキュメントは不可解です。

課題用紙言語のルールは単純です (今のところ @tags は無視しています)

  • プロジェクトは「:」で終わります
  • タスクは「-」で始まります
  • その他のテキスト行は、プロジェクトまたはタスクに関するプレーン テキストのメモです。

したがって、文字列 "Project 1:\nSome note\nProject 2:" は parseFile から [ProjectName("Project 1");NoteText("Some note");ProjectName("Project 2")] として返されるはずですが、代わりに、 get [ProjectName("プロジェクト 1");ProjectName("メモ\nプロジェクト 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 Software の TaskPaper アプリケーションTaskPaper の Web サイトから引用され ています 構文の例

    プロジェクト 1:
    プロジェクトワンの説明
    -プロジェクト 1 のタスク
    -プロジェクト 1 の別のタスク
    別のタスクの詳細
    ・最終課題

    店に行く:
    ・卵を買う
    ・牛乳を買う
4

1 に答える 1

3

私はFParsecに精通しているわけではありませんが、これはうまくいきます:

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 を数回使用しましたが、モナディック スタイルよりもコンビネーター スタイルを好みました。

于 2010-11-23T04:42:25.173 に答える