Я пытался использовать buildExpressionParser для анализа языка, и у меня это почти получилось. Благодаря Parsec.Expr повторный оператор Prefix/Postfix не поддерживается за решение одной из моих больших проблем.
Этот фрагмент кода иллюстрирует (на что я надеюсь) мою последнюю трудность:
import Text.Parsec.Expr
import Text.Parsec
data Expr = Lit Char | A1 Expr | A2 Expr | B Expr Expr
deriving (Show)
expr :: Parsec String () Expr
expr = buildExpressionParser table (fmap Lit digit)
prefix p = Prefix . chainl1 p $ return (.)
table =
[ [prefix $ char ',' >> return A1]
, [Infix (char '*' >> return B) AssocNone]
, [prefix $ char '.' >> return A2]]
Это успешно (и правильно) анализирует ,,0
, ..0
, .,0
, .0*0
и ,0*0
; однако он не может анализировать ,.0
или .0*.0
. Я понимаю, почему эти два не анализируются, но я не понимаю, как я могу изменить анализатор, чтобы ни один из успехов не изменился, а два неудачных анализа.
Один из способов «решить» это — изменить (fmap Lit digit)
на (fmap Lit Digit <|> expr)
, но тогда синтаксический анализатор зациклится, а не выдаст ошибку.
Совет приветствуется.
РЕДАКТИРОВАТЬ: Следующие синтаксические анализы являются ключевыми:
> parseTest expr ".0*0"
A2 (B (Lit '0') (Lit '0'))
> parseTest expr ",0*0"
B (A1 (Lit '0')) (Lit '0')