Domanda

Sto cercando di utilizzare fparsec per analizzare un linguaggio semplice todo list (i dati dal TaskPaper in realtà) come un semplice esempio parser combinatore. Ma ho incontrato un bug che non riesco a decifrare. Sono nuovo di combinatori parser e FParsec sembra contare su di me sapendo Parsec, ma sto trovando la documentazione di imperscrutabile parsec.

Le regole della lingua di carta compito sono semplici (sto ignorando @tags per ora)

  • Progetti terminare con un ':'
  • Le attività vengono iniziano con '-'
  • Ogni altra riga di testo è una nota di testo in chiaro sia sul progetto o attività

Quindi, la stringa "Progetto 1: \ nAlcuni nota \ nProject 2:" dovrebbe tornare dal ParseFile come [ProjectName ( "Progetto 1"); NoteText ( "qualche nota"); ProjectName ( "Progetto 2")], ma invece, ho [ProjectName ( "Progetto 1"); ProjectName ( "Alcuni nota \ nProject 2")]

Di seguito è riportato il mio codice parser.

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)

A cura

La sintassi è tratto dall'applicazione TaskPaper di Hogbay Software TaskPaper sito Alcuni esempi di sintassi

    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
È stato utile?

Soluzione

Io non sono super-fluente in FParsec, ma questo funziona:

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

codice stampa:

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

mi piacerebbe provarlo contro altri esempi.

A proposito:. Le poche volte che ho usato FParsec ho preferito lo stile combinatore sopra stile monadico

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top