2010-11-23 4 views
1

Ich versuche, eine einfache ToDo-Liste Sprache (die Daten aus Taskpaper tatsächlich) als einfaches Parser combinator Beispiel zu verwenden FParsec zu analysieren. Aber ich bin auf einen Fehler gestoßen, den ich nicht durcheinanderbringen kann. Ich bin neu bei Parser-Kombinatoren und FParsec scheint sich darauf zu verlassen, dass ich Parsec kenne, aber ich finde die Parsec-Dokumentation undurchschaubar.FParsec und ein Begrenzer basierte Syntax

Die Regeln der Aufgabe Papier Sprache sind einfach

  • Projekte am Ende mit einem (I @tags für jetzt bin ignorieren) ‚:‘
  • Aufgaben werden beginnen mit ‚-‘
  • Beliebig andere Textzeile ist eine einfache Textnotiz entweder auf dem Projekt oder eine Aufgabe

so ist die Zeichenfolge „Projekt 1: \ nEinige note \ nProject 2:“ von parseFile als [Projektnamen („Projekt 1“) zurückgeben sollte; NoteText ("Etwas Notiz"); ProjectName ("Projec t 2 ")], aber stattdessen bekomme ich [ProjectName (" Project 1 "); ProjectName (" Etwas Anmerkung \ nProject 2 ")]

Unten ist mein Parser-Code.

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) 

Herausgegeben

Die Syntax von Hogbay Software Taskpaper Anwendung TaskPaper website Einige Beispiele für die Syntax genommen wird

 
    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

lief ich den Code und bekam '[Notetext„Proje“]' –

+0

Können Sie einige repräsentative Proben von diesem Format veröffentlichen? –

+0

Dieser Code sieht für mich ok aus. Es wäre interessant, '\ n' durch '*' überall (einschließlich der Eingabe) und 'whiteSpace' durch' skipChar' * ''zu ersetzen, da dies wie ein Newline-Problem riecht. – Brian

Antwort

3

ich in FParsec nicht super fließend bin, aber dieses Werk :

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 

druckt:

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

Ich würde es gegen andere Beispiele testen.

BTW: die wenigen Male, die ich verwendet habe FParsec Ich habe den combinator Stil über monadischen Stil bevorzugt.

+0

Danke für Ihre Hilfe. Ich änderte parseFile zu 'Sebby parseLine (many1 (Newline <|> Leerzeichen))' meinetwegen. Was den Monad vs. Kombinator-Stil betrifft, erschrecken mich Funktionskombinatoren immer noch. Ich versuche, darüber hinwegzukommen, aber die monadische Syntax sieht mehr wie eine sichere, bequeme, imperative Kodierung aus. Außerdem denke ich, dass ich einen oder zwei neue F # -Syntax-Tricks von Ihrem Beispiel übernommen habe! – Ball

Verwandte Themen