2010-11-23 48 views
1

我想使用fparsec来解析简单的待办事项列表语言(实际上来自TaskPaper的数据)作为简单的分析程序组合器示例。但是我遇到了一个我似乎无法解决的bug。我是分析器组合器的新手,FParsec似乎依赖于我了解Parsec,但我发现parsec文档不可思议。FParsec和基于分隔符的语法

任务纸张语言的规则很简单(我忽略@tags现在)

  • 项目“结尾:”
  • 任务将开始“ - ”
  • 任何其他行文本是项目或任务上的纯文本注释

因此,字符串“Project 1:\ nSome note \ nProject 2:”应该从parseFile返回为[ProjectName(“Project 1”); NoteText(“Some note”); ProjectName(“Projec t 2“)],但是相反,我得到[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”]` – 2010-11-23 03:40:29

+0

你可以发布这种格式的代表性样本? – 2010-11-23 03:43:30

回答

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我更喜欢一元风格的combinator风格。