Синтаксический анализ комментариев к блоку Megaparsec с использованием символов начала и конца
Я хочу проанализировать текст, похожий на этот в Haskell, используя Megaparsec.
# START SKIP
def foo(a,b):
c = 2*a # Foo
return a + b
# END SKIP
, где # START SKIP
а также # END SKIP
отмечает начало и конец блока текста для анализа.
По сравнению с skipBlockComment я хочу, чтобы парсер возвращал строки между маркером начала и конца.
Это мой парсер.
skip :: Parser String
skip = s >> manyTill anyChar e
where s = string "# START SKIP"
e = string "# END SKIP"
skip
Парсер работает как задумано.
Чтобы разрешить переменное количество пустого пространства в начале и конце маркера, например # START SKIP
Я пробовал следующее:
skip' :: Parser String
skip' = s >> manyTill anyChar e
where s = symbol "#" >> symbol "START" >> symbol "SKIP"
e = symbol "#" >> symbol "END" >> symbol "SKIP"
С помощью skip'
для разбора вышеприведенного текста выдается следующая ошибка.
3:15:
unexpected 'F'
expecting "END", space, or tab
Я хотел бы понять причину этой ошибки и как я могу это исправить.
1 ответ
Как уже заметил Алек, проблема в том, что как только e
встречи '#'
, он считается потребляемым персонажем. И способ работы parsec и его производных заключается в том, что как только вы используете любые символы, вы переходите на эту ветвь синтаксического анализа - т.е. manyTill anyChar
альтернатива тогда не рассматривается, даже если e
в конечном итоге терпит неудачу здесь.
Вы можете легко запросить возврат, хотя, оборачивая конечный разделитель в try
:
skip' :: Parser String
skip' = s >> manyTill anyChar e
where s = symbol "#" >> symbol "START" >> symbol "SKIP"
e = try $ symbol "#" >> symbol "END" >> symbol "SKIP"
Это тогда будет, прежде чем потреблять '#'
установить "контрольную точку", и когда e
не удается позже (в вашем примере, в "Foo"
), он будет действовать так, как если бы ни один символ не совпадал вообще.
На самом деле, традиционный парсек даст такое же поведение и для skip
, Просто потому, что поиск строки и ее успешное выполнение только в том случае, если она полностью совпадает, является такой распространенной задачей, мегапарсек string
реализован как try . string
То есть, если сбой происходит в пределах этой фиксированной строки, он всегда будет возвращаться назад.
Однако составные парсеры по-прежнему не возвращаются по умолчанию, как в attoparsec. Основная причина заключается в том, что если что-то может вернуться к какой-либо точке, вы не сможете получить четкую точку сбоя в сообщении об ошибке.