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

В Parsec есть ли способ предотвратить лексему от употребления новых строк?

Все парсеры в Text.Parsec.Token вежливо используют lexeme, чтобы есть пробелы после токена. К сожалению, для меня пробелы включают новые строки, которые я хочу использовать в качестве терминаторов выражения. Есть ли способ убедить lexeme оставить новую строку?

4b9b3361

Ответ 1

Нет, это не так. Вот соответствующий код.

От Text.Parsec.Token:

lexeme p
    = do{ x <- p; whiteSpace; return x  }


--whiteSpace
whiteSpace
    | noLine && noMulti  = skipMany (simpleSpace <?> "")
    | noLine             = skipMany (simpleSpace <|> multiLineComment <?> "")
    | noMulti            = skipMany (simpleSpace <|> oneLineComment <?> "")
    | otherwise          = skipMany (simpleSpace <|> oneLineComment <|> multiLineComment <?> "")
    where
      noLine  = null (commentLine languageDef)
      noMulti = null (commentStart languageDef)

В предложении where whitespace можно заметить, что единственные варианты рассматривались с комментариями. Функция lexeme использует whitespace, и она используется либерально в остальной части parsec.token.


Обновление от 28 сентября 2015 г.

Конечным решением для меня было использование правильного лексического анализатора (alex). Parsec отлично работает в качестве библиотеки для синтаксического анализа, и это кредит для дизайна, который может быть искажен в лексическом анализе, но для всех, кроме небольших и простых проектов, он быстро станет громоздким. Теперь я использую alex для создания линейного набора токенов, а затем Parsec превращает их в AST.

Ответ 2

Если новые строки являются вашими терминаторами выражения, возможно, имеет смысл разделить входные данные на каждой новой строке и самостоятельно разобрать каждую строку.

Ответ 3

Ну, не все парсеры в Text.Parsec.Token используют lexeme, хотя все они должны. Хуже всего это не задокументировано, кто из них потребляет белый пространства, а какие нет. Некоторые из парсеров в Text.Parsec.Token потребляют пробел после лексемы, некоторые из них этого не делают. Некоторые из них потребляют также ведущие пробелы. Вы должны прочитать существующие проблемы на GitHub, если вы хотите полностью контролировать ситуацию.

В частности:

  • decimal, hexadecimal и octal парсеры не потребляют трейлинг пробел, см. источник, и этот вопрос;

  • integer также потребляет ведущие пробелы, см. этот вопрос;

  • остальные из них, вероятно, потребляют конечные пробелы и, следовательно, новые строки, это, однако, трудно сказать наверняка, потому что код Parsec особенно волосатые (ИМХО), и проект не имеет набора тестов (за исключением 3 тесты, которые проверяют, что уже исправленные ошибки не отображаются снова, однако этого недостаточно для предотвращения регрессий, и каждое изменение в источнике может разорвать ваш код в следующей версии Parsec.)

Существуют различные предложения, как сделать его настраиваемым (что должно быть считается белым пространством), ни одна из них по какой-либо причине не объединяется и не комментируется.

Но реальная проблема заключается скорее в дизайне Text.Parsec.Token, который блокирует пользователя в решения, построенные makeTokenParser. Этот дизайн особенно негибкий. Существует много случаев, когда только одно решение заключается в копировании весь модуль и отредактировать его по мере необходимости.

Но если вам нужен современный и последовательный Parsec, есть возможность переключиться на Megaparsec, где это (и многие другие) проблема не существует.


Раскрытие информации: Я один из авторов Megaparsec.

Ответ 4

Хотя другие ответы об этом невозможны, верны, я хотел бы указать, что синтаксические пары char не используют парсер lexeme.
Я использую parsec для анализа некоторых html-шаблонов усов. В этом анализе важны пробелы. Я просто разбирал строки " > " и "}} с помощью Text.Parsec.Char.string.
Поскольку меня интересуют пробелы между тегами, а не внутри них, я все же могу использовать зарезервированные операторы для анализа "<" и "{{" и т.д., потому что лексемный парсер потребляет только конечные пробелы.