Пример простого списка FParsec - PullRequest
2 голосов
/ 08 июля 2019

Я только начинаю работать с FParsec и не могу обернуться вокруг простого анализатора списков. С учетом ввода

"{ a;b;c d; }"

Я хочу получить результат ['a';'b';'c';'d']

Если я делаю

let baseChars = ['0'..'9'] @ ['A'..'Z'] @ ['a'..'z'] @ ['_'; '-']
let chars : Parser<_> = anyOf baseChars
let nameChars : Parser<_> = anyOf (baseChars @ ['.'])                

let semiColonList p : Parser<_> = sepBy p (pstring ";")
let pList p : Parser<_> = between (pstring "{") (pstring "}") (semiColonList p)

do  """{
    a;b;c;
    d;
}"""
    |> run (parse {
        let! data = pList (spaces >>. many1Chars nameChars)
        return data
    })
    |> printfn "%A"

Я получаю ошибку на последнем}, так как он пытается сопоставить это с парсером nameChars перед закрытием парсера между. Такое ощущение, что есть простое решение, которое я пропускаю, тем более, что если я удаляю последнюю точку с запятой после того, как d все работает как ожидалось. Любая помощь приветствуется.

[править] Благодаря Федору Сойкину работают:

    let semiColonList p = many (p .>> (pstring ";" >>. spaces))
    let pList p : Parser<_> = between (pstring "{") (pstring "}") (semiColonList p)
    """{
    a;b;c;
    d;
}"""
    |> run (parse {
        let! data = pList (spaces >>. many1Chars nameChars)
        return data
    })
    |> printfn "%A" 

1 Ответ

3 голосов
/ 09 июля 2019

sepBy не допускает конечный разделитель. Парсер, подобный sepBy a b, предназначен для синтаксического анализа ввода, например, a b a b a, но ваш ввод похож на a b a b a b - в конце есть дополнительный разделитель b.

Вместо этого вы хотите проанализировать несколько выражений, подобных a b, что даст вам желаемую форму ввода.

Чтобы разобрать одно из таких выражений, используйте оператор секвенирования .>>, а чтобы проанализировать несколько таких пар, используйте many:

semiColonList p = many (p .>> pstring ";")
...