Подтвердить что ты не робот

Может ли библиотека Haskell Parsec использоваться для реализации рекурсивного парсера с резервным копированием?

Я рассматриваю возможность использования библиотеки разбора Haskell Parsec для анализа подмножества Java как рекурсивного парсера спуска в качестве альтернативы более традиционным решениям парсера-генератора, таким как Happy. Parsec кажется очень простым в использовании, и скорость разбора определенно не является для меня фактором. Мне интересно, однако, если возможно реализовать "резервное копирование" с Parsec, метод, который находит правильное производство для использования, пытаясь каждый из них по очереди. Для простого примера рассмотрим начало Java-грамматики JLS:

Literal:
    IntegerLiteral  
    FloatingPointLiteral

Я бы хотел, чтобы не нужно было выяснить, как я должен заказать эти два правила, чтобы заставить синтаксический анализ добиться успеха. Как бы то ни было, наивная реализация такая:

literal = do {
    x <- try (do { v <- integer; return (IntLiteral v)}) <|>
         (do { v <- float; return (FPLiteral v)});
    return(Literal x)
}

Не будет работать... Входы, такие как "15.2", заставят целочисленный синтаксический анализатор быть успешным первым, а затем все это задохнется на ".". символ. В этом случае, конечно, очевидно, что вы можете решить эту проблему, переупорядочив две постановки. В общем случае, однако, поиск подобных вещей будет кошмаром, и очень вероятно, что я пропущу некоторые случаи. В идеале, я бы хотел, чтобы Parsec выяснял такие вещи, как это для меня. Возможно ли это, или я просто пытаюсь сделать слишком много с библиотекой? Документация Parsec утверждает, что она может "анализировать контекстно-зависимые, бесконечные грамматические символы с перспективой", поэтому мне кажется, что я должен что-то сделать здесь.

4b9b3361

Ответ 1

Используйте Parsec notFollowedBy, чтобы гарантировать, что integer потребляет все до некоторого разделителя маркеров (этот подход будет масштабироваться до произвольного сценария большую часть времени) или взглянуть на комбинаторы парсеров, которые исследуют все возможные варианты синтаксического анализа. Прежде всего, чтобы прийти в голову, библиотека UU_Parsing.

Ответ 2

Один из способов сделать это - использовать комбинатор try, который позволяет синтаксическому анализатору принимать входные данные и терпеть неудачу без сбоев в синтаксическом анализе.

Другим является использование Text.ParserCombinators.ReadP, которое реализует симметричный оператор выбора, в котором доказано, что a +++ b = b +++ a, поэтому на самом деле не имеет значения, какой порядок. Я довольно неполный к ReadP, поскольку он минимален, но обеспечивает то, что вам нужно, чтобы создать действительно мощный синтаксический анализатор.