Как написать парсер парсека для списка вкрапленных элементов?

Допустим, ввод выглядит примерно так foo#1 bar baz-3.qux [...]. Я хочу написать синтаксический анализатор, который потребляет ввод только до первого пробела перед [, что означает foo#1 bar baz-3.qux (без завершающего пробела).

Как мне подойти к этому с помощью парсека?

Я могу представить что-то вроде

foo = many1 $ letter <|> digit <|> oneOf " #-."

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

P.S. Я ищу максимально общее решение, а не хитрый хак, который решит этот конкретный пример.


person Jakub Arnold    schedule 07.06.2014    source источник
comment
Работают ли sepBy и sepBy1?   -  person J. Abrahamson    schedule 07.06.2014


Ответы (1)


Я думаю, что вы ищете именно notFollowedBy. Что-то типа

foo = many1 $     letter 
              <|> digit 
              <|> oneOf "#-." 
              <|> (try $ char ' ' >> notFollowedBy (char '[') >> return ' ')

Вы можете абстрагироваться от шаблона, чтобы получить общую функцию, конечно:

endedBy :: (Show y) => Parser x -> Parser x -> Parser y -> Parser [x]
endedBy p final terminal = many1 $ p <|> t where 
  t = try $ do
        x <- final
        notFollowedBy terminal
        return x

foo' = endedBy (letter <|> digit <|> oneOf "#-.") (char ' ') (char '[')
person user2407038    schedule 07.06.2014