Pergunta

Estou tentando usar o FPARSEC para analisar um idioma simples da lista de tarefas (os dados do papel de tarefa realmente) como um exemplo simples de combinador de analisador. Mas eu encontrei um bug que não consigo entender. Sou novo nos combinadores de analisador e o FPARSEC parece confiar em mim conhecendo o parsec, mas estou encontrando a documentação do parsec inescrutável.

As regras da linguagem do papel de tarefa são simples (estou ignorando @Tags por enquanto)

  • Os projetos terminam com um ':'
  • As tarefas são iniciadas com '-'
  • Qualquer outra linha de texto é uma nota de texto simples no projeto ou tarefa

Portanto, a string "Projeto 1: Nome Nota nProject 2:" deve retornar do parsefile como [ProjectName ("Projeto 1"); NoteText ("Alguns Nota"); ProjectName ("Projeto 2")], mas, em vez disso, I I get [ProjectName ("Projeto 1"); ProjetoName ("Algumas Notas nProject 2")]

Abaixo está o meu código de analisador.

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)

Editado

A sintaxe é retirada do aplicativo de papel de tarefa do software Hogbay Site de papel de tarefaAlguns exemplos da sintaxe

    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
Foi útil?

Solução

Não sou super fluente no FPARSEC, mas este funciona:

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

Imprime:

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

Eu testaria contra outros exemplos.

BTW: As poucas vezes em que usei o FPARSEC Eu preferia o estilo combinador ao longo do estilo Monadic.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top