он не анализирует никакие Dotted, потому что первый параметр всегда успешно разбирает первый фрагмент строки.
Эта проблема может быть достаточно легко решена путем изменения порядка ваших альтернатив. Как правило, всякий раз, когда у вас есть альтернатива, которая может всегда совпадать, эта альтернатива должна быть последней.
Однако это приведет вас только к следующей проблеме: ваш Dotted
синтаксический анализатор является леворекурсивным, что parsec не поддерживает, то есть он приведет к бесконечной рекурсии, как только он действительно достигнут.
Обычно, когда мы хотим использовать леворекурсивную грамматику с алгоритмом синтаксического анализа, который не обрабатывает левую рекурсию, мы заменяем рекурсию повторением, а затем выполняем левый сгиб в результирующем списке. Итак, учитывая оригинальную грамматику:
foo ::= alphanum
| foo "." alphanum
Мы можем переписать его, используя повторение так:
foo ::= alphanum ("." alphanum)*
Теперь самый прямой перевод в Parsec будет использовать many
для *
, а затем свернуть влево полученный список. Тем не менее, мы могли бы заметить, что шаблон rule ("seperator" rule)*
может быть проще сопоставлен с sepBy1
. Так что это дает нам:
fooParser =
do
first : rest <- sepBy1 alphanum $ constant "."
return $ foldl Dotted (Simple first) rest