Я пытаюсь разделить свой ввод на те части, которые соответствуют определенному шаблону, а остальные, скажем,
data Data = A Int | B Char | C String
parseDatas :: Parsec [Token] () a [Data]
Я уже написал два более-менее сложных парсера
parseA :: Parsec [Token] () Data
parseB :: Parsec [Token] () Data
которые соответствуют вещам, которые я ищу. Теперь очевидное решение
parseDatas = many (parseA <|> parseB <|> parseC)
где парсер для промежуточных частей будет выглядеть так:
makeC :: [Token] -> Data
makeC = C . concatMap show -- or something like this
parseC :: Parsec [Token] () Data
parseC = makeC <$> many anyToken
Мех, это выдает среду выполнения [ERROR] Text.ParserCombinators.Parsec.Prim.many: combinator 'many' is applied to a parser that accepts an empty string.
- хорошо, это легко исправить:
parseC = makeC <$> many1 anyToken
Но теперь parseC
потребляет весь ввод (который начинается с чего-то, что я не ищу), игнорируя любые шаблоны, которые должны дать A
или B
!
Если бы мои шаблоны были регулярными выражениями1, я бы сейчас заменил оператор +
на нежадный оператор +?
. Как сделать то же самое для комбинатора парсера many1
?
1: который я не могу использовать, так как работаю с токенами, а не с символами
Решение, которое я нашел, было
parseC = makeC <$> many1 (notFollowedBy (parseA <|> parseB) >> anyToken)
но это выглядит, ммм, неоптимально. Это не совсем универсально. Должно быть что-то лучше.
Я также просмотрел Parsec, как найти совпадения в строке, где предлагалось определить рекурсивный синтаксический анализатор, но это выглядит как проблема, если я не хочу отбрасывать промежуточные токены и вместо этого собирать их в список.